I'm facing an issue with my Spring Boot application. When I run the app directly from my IDE, everything works fine — I can log in from my Angular frontend (via POST /login) without any problems.
However, after I've packaged the app into a JAR file using mvn clean install and run it with java -jar my-app.jar, I get the following behavior:
Logging in via Postman or Insomnia still works (POST request to /login returns token as expected).
Logging in via the Angular frontend (in the browser) fails with a 403 Forbidden error.
Backend logs show:
HttpRequestMethodNotSupportedException: Request method 'GET' is not supported
What I've checked:
- CORS configuration in SecurityConfiguration allows
http://localhost:4200and includes POST method.
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.cors(cors -> cors.configurationSource(request -> {
var corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOriginPatterns(List.of("http://localhost:4200"));
corsConfiguration.setAllowedMethods(List.of("GET","PATCH", "POST", "PUT", "DELETE", "OPTIONS"));
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Content-Type"));
corsConfiguration.setAllowCredentials(true);
return corsConfiguration;
}))
.authorizeHttpRequests(request -> request
.requestMatchers("/","/login","/join").permitAll()
.requestMatchers("/users").hasRole("ADMIN")
.requestMatchers("/uploads/**").permitAll()
.anyRequest().authenticated())
.sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
.authenticationProvider(authenticationProvider())
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
- Angular is sending a POST request to
/login.
login(loginRequest: LoginRequest): Observable {
this.dataService.log(true);
return this.http.post(`${environment.baseURL}/login`, loginRequest
)
.pipe(
tap((response: AuthResponse) => {
if (response.token) {
localStorage.setItem('jwtToken', response.token);
}
}),
catchError(error => {
console.error('Login error:', error);
return throwError(() => new Error(error.error?.message || 'Login failed. Please try again.'));
})
);
}
- Angular interceptor:
export const headerInterceptor: HttpInterceptorFn = (req: HttpRequest,
next: HttpHandlerFn
): Observable> => {
const Authorization = localStorage.getItem('jwtToken') ? `Bearer ${localStorage.getItem('jwtToken')}` : '';
if(!req.url.includes('login') && !req.url.includes('join'))
return next(req.clone({ setHeaders: { Authorization } }));
else
return next(req);
};
- environment.prod.ts:
export const environment = {
production: true,
baseURL: "http://localhost:8080",
eventsURL: "http://localhost:8080/events",
homeURL: "http://localhost:8080/home",
citiesURL: "http://localhost:8080/cities",
commentsURL: "http://localhost:8080/comments",
usersURL: "http://localhost:8080/users"
};
- and in angular.json:
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
- in application.yml:
profiles:
active: prod
- start .jar with
java -jar my-app.jar --spring.profiles.active=prod
Works perfectly in IDE.
Fails only after running from the JAR.
No apparent difference in logs or stack traces that explain why only browser requests fail.
Question:
What could cause Spring Boot to behave differently (especially for browser-based login requests) when running from a JAR versus running from the IDE?