OKTA integration with Spring Boot project

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.

1 Like

You should be using the “default” authorization server, which means you should change your okta.oauth2.issuer to https://{Company}.okta.com/oauth2/default
And also okta.oauth2.discovery-uri to https://{Company}.okta.com/oauth2/default/.well-known/openid-configuration

Refer to this section - https://github.com/okta/okta-spring-boot#configure-your-properties

Let me know if this works.

Regards,
Vijet

Initially I tried with /oauth2/default/.well-known/openid-configuration but navigating to the page gives me an error as follows

{“errorCode”:“E0000015”,“errorSummary”:“You do not have permission to access the feature you are requesting”,“errorLink”:“E0000015”,“errorId”:“oaeZ3FNDVr7SOyjkGxHeuC0rw”,“errorCauses”:[]}

That is why I had to use the URL minus /oauth2/default

Oh… In that case, you will need to create an authorization server that’ll protect your resources.
And then use the issuerUrl of the server in your project.
You can follow the instructions here to create a custom auth server - https://developer.okta.com/authentication-guide/implementing-authentication/set-up-authz-server.html

Let me know if this helps.

Hey @dpancs!

Depending on when your Okta Org was created you may need to create your Authorization Server (newly created accounts have the ‘default’ one created for you)

Take a look at this link for details on creating one: https://developer.okta.com/authentication-guide/implementing-authentication/set-up-authz-server.html

For some reason my organization doesn’t have the option under API for Authorization Server. I only see Tokens and Trusted Origins.

Can you post a screenshot?
Also, is this a developer account created using the sign up page on developer.okta.com?

I am extremely apologetic as I didn’t realize the questions posted here are only relevant to the developer account. I did create a developer account and see the Authorization Servers as a tab. I was logged into my organization’s enterprise account and that doesn’t seem to have the tab.API PAGE

A huge thanks to @vijet and @bdemers for being super responsive and awesome!

You’re welcome @dpancs!
Try out your code with the developer account org and it should work.

To use the functionality in your IT Product org, you will need to get API Access Manager as a Product.