I am trying to integrate OKTA into my Spring Boot (1.5.6.Release) application using the okta-spring-boot-starter library. I am navigated correctly to the hosted login page at Okta but on entering my credentials, I am getting an error as follows:
Authentication Failed: Could not obtain user details from token
On debugging the issue, I noticed that the exact error occurs in OAuth2ClientAuthenticationProcessingFilter.java → method attemptAuthentication(HttpServletRequest request, HttpServletResponse response) on line
OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
The error thrown is
error=“invalid_token”, error_description=“Invalid JOSE Header kid (uwPityHrOLCxpQdAYpSGUnG48j_qHj0EcFdLWLeMb3s)”
My bootstrap.properties file
okta.oauth2.issuer:https://{Company}.okta.com
okta.oauth2.audience:{myAudience}
okta.oauth2.clientId:{myClientId}
okta.oauth2.clientSecret:{myClientSecret}
okta.oauth2.discovery-uri=https://{Company}.okta.com/.well-known/openid-configuration
My ApplicationSecurity.java file
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@EnableWebSecurity
@EnableOAuth2Sso
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private AutowireCapableBeanFactory beanFactory;
@Autowired
private UserService userService;
public ApplicationSecurity() {
super();
}
public ApplicationSecurity(boolean disableDefaults) {
super(disableDefaults);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(switchUserFilter(), FilterSecurityInterceptor.class).
addFilterBefore(getCustomerResolverFilter(), UsernamePasswordAuthenticationFilter.class);
http.headers()
.httpStrictTransportSecurity().includeSubDomains(true).maxAgeInSeconds(31536000);
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/secure/**", "/services/v1/**").authenticated()
.and()
.formLogin()
.loginPage("/login").loginProcessingUrl("/login_check").successHandler(successHandler()).
failureHandler(failureHandler())
.permitAll()
.and()
.logout().logoutUrl("/logout").deleteCookies().invalidateHttpSession(true).logoutSuccessHandler(logoutSuccessHandler())
.permitAll();
http.exceptionHandling().authenticationEntryPoint(getAuthenticationEntryPoint());
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/scripts/**").antMatchers("/WEB-INF/views/**").antMatchers("/WEB-INF/images/**");
}
@Bean
public CustomAuthenticationSuccessHandler successHandler() {
CustomAuthenticationSuccessHandler successHandler = new CustomAuthenticationSuccessHandler();
return successHandler;
}
@Bean
public CustomAuthenticationFailureHandler failureHandler() {
CustomAuthenticationFailureHandler failureHandler = new CustomAuthenticationFailureHandler();
return failureHandler;
}
@Bean
public AuthenticationEntryPoint getAuthenticationEntryPoint() {
return new AuthenticationEntryPoint("/login");
}
@Bean
public CustomLogoutSuccessHandler logoutSuccessHandler() {
return new CustomLogoutSuccessHandler();
}
@Bean(name = "slowPasswordEncoder")
public PasswordEncoder slowPasswordEncoder() {
return new BCryptPasswordEncoder(12);
}
@Bean(name = "userDetailsService")
public UserDetailsService userDetailsServiceImpl() {
return new CustomUserDetailsService();
}
@Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsServiceImpl());
authProvider.setPasswordEncoder(passwordEncoder());
authProvider.setUserService(userService);
authProvider.setSlowPasswordEncoder(slowPasswordEncoder());
return authProvider;
}
@Bean
public SwitchUserFilter switchUserFilter() {
SwitchUserFilter filter = new SwitchUserFilter();
filter.setUserDetailsService(userDetailsServiceImpl());
//After succesfull login we will go to the /secure/index
filter.setSuccessHandler(successHandler());
filter.setFailureHandler(failureHandler());
return filter;
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public RedirectStrategy getRedirectStrategy() {
DefaultRedirectStrategy defaultRedirectStrategy = new DefaultRedirectStrategy();
return defaultRedirectStrategy;
}
@Bean
public Filter getCustomerResolverFilter() {
CustomerResolverFilter customerResolverFilter = new CustomerResolverFilter();
beanFactory.autowireBean(customerResolverFilter);
return customerResolverFilter;
}
}
These are the only changes I have made to my application. Any help or pointers are greatly appreciated.