I am making a full stack application for my TFC, using Java with Spring Boot for the backend and Angular with the frontend. However, when making GET
requests, Spring Boot security rejects my requests.
These are the Spring Boot security logs that I get:
2024-12-23T12:42:44.562+01:00 INFO 14252 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-12-23T12:42:44.562+01:00 INFO 14252 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2024-12-23T12:42:44.565+01:00 INFO 14252 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
2024-12-23T12:42:44.594+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Securing GET /park/emergencies
2024-12-23T12:42:44.594+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing GET /park/dinosaurs
2024-12-23T12:42:44.594+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Securing GET /park/enclosures
2024-12-23T12:42:44.595+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /park/status
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.790+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing GET /error
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-1] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-4] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-2] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:44.801+01:00 DEBUG 14252 --- [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:45.892+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : Securing PUT /park/update
2024-12-23T12:42:45.897+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
2024-12-23T12:42:45.898+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : Securing PUT /error
2024-12-23T12:42:45.900+01:00 DEBUG 14252 --- [nio-8080-exec-5] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
I have compared the two tokens, the frontend and the backend and they are the same so I don’t know why they are rejecting my requests.
This is the class where I configure the CORS:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtFilter jwtFilter;
@Autowired
public SecurityConfig(JwtFilter jwtFilter){
this.jwtFilter=jwtFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/auth/register", "/auth/login").permitAll()
.anyRequest().authenticated()
)
.anonymous(AbstractHttpConfigurer::disable)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type", "Accept"));
configuration.setExposedHeaders(List.of("Authorization"));
configuration.setMaxAge(3600L);
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
This is the JwtFilter
:
@Component
public class JwtFilter implements Filter {
private final JwtUtil jwtUtil;
@Autowired
public JwtFilter(JwtUtil jwtUtil){
this.jwtUtil=jwtUtil;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authHeader = httpRequest.getHeader("Authorization");
// System.out.println(authHeader+" solicitud desde el fornted");
String path = httpRequest.getRequestURI();
if ( path.startsWith("/auth")) {
chain.doFilter(request, response);
return;
}
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
try {
String userId=jwtUtil.validateToken(token);
httpRequest.setAttribute("userId",userId);
System.out.println("Token válido. UserId extraído: " + userId+" token "+authHeader);
} catch (Exception e) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
// System.out.println("Error al validar el token de jwt filter " + e.getMessage()+ " "+token);
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token inválido");
return;
}
}
chain.doFilter(request, response);
}
And this is the class that I use to generate the token
@Component
public class JwtUtil {
@Value("${jwtKey}")
private String secretKey;
@Value("${jwtKeyExpiration}")
private long keyExpiration;
private Key key;
@PostConstruct
public void init() {
key = Keys.hmacShaKeyFor(secretKey.getBytes());
}
//genero un token con enlazado con el id del usuario mi key, que durara una 1 hora(despues el usuario
//Tendra que iniciar sesion de nuevo
public String generateToken(String userId) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.claims(claims)
.subject(userId)
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + keyExpiration))
.signWith(key, SignatureAlgorithm.HS256)
.compact();
}
public String validateToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(key)
.build()
.parseSignedClaims(token)
.getPayload();
return claims.getSubject();
}
}
What can I do to fix the 403 CORS errors?
First I compared the tokens, and if the backend sent them correctly to the frontend at login, and if it was the same.
I have also reviewed other posts on this site, about the securing error, and it has not worked for me.
The CORS error that I get is:
Request URL:
http://localhost:8080/park/update
Request Method:
PUT
Status Code:
403 Forbidden
Remote Address:
[::1]:8080
Referrer Policy:
strict-origin-when-cross-origin
access-control-allow-credentials:
true
access-control-allow-origin:
http://localhost:4200
access-control-expose-headers:
Authorization
cache-control:
no-cache, no-store, max-age=0, must-revalidate
connection:
keep-alive
content-length:
0
date:
Mon, 23 Dec 2024 11:47:17 GMT
expires:
0
keep-alive:
timeout=60
pragma:
no-cache
vary:
Origin
vary:
Access-Control-Request-Method
vary:
Access-Control-Request-Headers
x-content-type-options:
nosniff
x-frame-options:
DENY
x-xss-protection:
0
accept:
application/json, text/plain, */*
accept-encoding:
gzip, deflate, br, zstd
accept-language:
es-ES,es;q=0.9
authorization:
Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzM0OTUzMTM0LCJleHAiOjE3MzQ5NTY3MzR9.x6VAuPFWyr2AaASPMO3Th7_6d7MDRyoEuwVdlxJf95U
connection:
keep-alive
content-length:
0
host:
localhost:8080
origin:
http://localhost:4200
referer:
http://localhost:4200/
sec-ch-ua:
"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
sec-ch-ua-mobile:
?0
sec-ch-ua-platform:
"Windows"
sec-fetch-dest:
empty
sec-fetch-mode:
cors
sec-fetch-site:
same-site
user-agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
This is the interceptor that I use in frontend:
export const authInterceptor: HttpInterceptorFn = (req: HttpRequest<any>, next: HttpHandlerFn): Observable<HttpEvent<any>> => {
const token = localStorage.getItem('token');
console.log("El token es del fronted "+token)
const clonedRequest = token
? req.clone({
setHeaders: {
Authorization: `Bearer ${token}`,
},
withCredentials: true
})
: req.clone({ withCredentials: true });
return next(clonedRequest);
};
Quenuo Real is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
4