I'm trying to use Github OAuth2 authentication on spring boot project with spring security, but the problem that the redirect URI is not found. It matches the one on github.
This is the code of the security config:
package eu.tasgroup.applicativo.conf;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import eu.tasgroup.applicativo.filter.JwtAuthenticationFilter;
import eu.tasgroup.applicativo.repository.AmministratoriRepository;
import eu.tasgroup.applicativo.repository.ClientiRepository;
import eu.tasgroup.applicativo.repository.PermessiAmministratoriRepository;
import eu.tasgroup.applicativo.security.JwtAuthenticationEntryPoint;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final ClientiRepository cr;
private final AmministratoriRepository ar;
private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final PermessiAmministratoriRepository pr;
private CostumerUserDetailsService cs;
public SecurityConfig(ClientiRepository cr, AmministratoriRepository ar, PermessiAmministratoriRepository pr,
JwtAuthenticationFilter jwtAuthenticationFilter, CostumerUserDetailsService cs, JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint) {
this.cr = cr;
this.ar = ar;
this.pr = pr;
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.cs = cs;
}
@Bean
@Order(2)
SecurityFilterChain adminFilterChain(HttpSecurity http, CustomAuthenticationFailureHandler failureHandler,
CustomAuthenticationSuccessHandler successHandler) throws Exception {
http.securityMatcher("/admin/**")
.authorizeHttpRequests(
(authorize) -> authorize.requestMatchers(PathRequest.toStaticResources().atCommonLocations())
.permitAll().requestMatchers("/admin/admin-registrazione").permitAll()
.requestMatchers("/admin/admin-form-registrazione").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN"))
.formLogin((form) -> form.loginPage("/admin/admin-login").failureHandler(failureHandler)
.successHandler(successHandler).usernameParameter("email").permitAll())
.logout((logout) -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/admin/admin-logout"))
.logoutSuccessUrl("/").invalidateHttpSession(true).clearAuthentication(true).permitAll());
return http.build();
}
@Bean
@Order(3)
SecurityFilterChain userFilterChain(HttpSecurity http, CustomAuthenticationFailureHandler failureHandler,
CustomAuthenticationSuccessHandler successHandler) throws Exception {
http.securityMatcher("/user/**")
.authorizeHttpRequests(
authorize -> authorize.requestMatchers(PathRequest.toStaticResources().atCommonLocations())
.permitAll().requestMatchers("/user/user-registrazione").permitAll()
.requestMatchers("/user/user-form-registrazione").permitAll()
.requestMatchers("/user/**").hasRole("USER"))
.formLogin(form -> form.loginPage("/user/user-login").usernameParameter("email")
.failureHandler(failureHandler).successHandler(successHandler).permitAll())
.logout(logout -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/user/user-logout"))
.logoutSuccessUrl("/").permitAll());
return http.build();
}
@Bean
@Order(1)
SecurityFilterChain githubOAuth2FilterChain(HttpSecurity http, CustomAuthenticationFailureHandler failureHandler,
CustomAuthenticationSuccessHandler successHandler) throws Exception {
http.securityMatcher("/oauth2/**").authorizeHttpRequests( (authorizeRequests) -> authorizeRequests
.requestMatchers("/").permitAll()
.anyRequest().authenticated())
.oauth2Login(oauth2 -> oauth2
.failureUrl("/user/user-login")
.userInfoEndpoint(infoEndpoint ->
infoEndpoint.userService(cs)))
.logout(logout -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/user/user-logout"))
.logoutSuccessUrl("/").permitAll());
return http.build();
}
@Bean
@Order(4)
SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http.securityMatcher("/api/**")
// Abilita CORS e disabilita CSRF
.cors(cors -> cors.configurationSource(corsConfigurationSource())).csrf(csrf -> csrf.disable())
// setto sessione stateless
.sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// gestisco eccezioni per request non autorizzate
.exceptionHandling(handling -> handling.authenticationEntryPoint(jwtAuthenticationEntryPoint))
// setto permessi per endpoints pubblici
// setto endpoint privati
.authorizeHttpRequests(auth -> auth.requestMatchers("/api/login").permitAll().anyRequest().authenticated())
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(new CostumerUserDetailsService(ar, cr, pr));
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
UrlBasedCorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("http://localhost:4200"); // Uso di pattern
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
I tried to exclude the uri from the Jwt filter, exclude it from the static resource mapping, but still i receive 404 not found error
In the console i noticed:
Securing GET /oauth2/ Set SecurityContextHolder to anonymous SecurityContext
Saved request http://localhost:8080/oauth2/?continue to session Redirecting to http://localhost:8080/oauth2/authorization/todo
Securing GET /oauth2/authorization/todo
GET "/login/oauth2/code/github?code=7dbd4161ce384dca7df2&state=xqHtfEOaN6Y4103mTO64Tv-1H9ZIITPivoliIHjixEM%3D", parameters={masked}
Application Properties:
spring.security.oauth2.client.registration.todo.client-id=XXXXXXXXXXXXXXXXXXXXXX
spring.security.oauth2.client.registration.todo.client-name=AppName
spring.security.oauth2.client.registration.todo.provider=github
spring.security.oauth2.client.registration.todo.client-secret=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
spring.security.oauth2.client.registration.todo.scope=user
spring.security.oauth2.client.registration.todo.redirect-uri=http://localhost:8080/login/oauth2/code/github
I managed to solve this by setting also the callback uri in the security matcher.