Post process Okta auth code flow

I’ve developed a basic application using Spring Boot 2.1.7. Here is a snippet of my WebSecurityConfig:

protected void configure(HttpSecurity http) throws Exception
{
    http.authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .oauth2Login()
        .successHandler(customOauthLoginSuccessHandler())
        .failureHandler(customOauthLoginFailureHandler())
        .and()
        .oauth2Client();

    http.csrf().disable();
}

I have an application.yml that is correctly configured with issuer, client-id and client-secret. Also, I have configured a custom success handler which gets fired after login.

All resources are secured so accessing http://localhost:8080/ correctly sends me to the Okta login and there I can enter my credentials and get redirected back to localhost to display a hello world page. It is a basic working example that can be found easily.

I’ve been trying, without success, to implement custom code that can be injected in the authentication flow. The placement of the code should be after back-channel http requests are complete but before the success handler is called. The purpose of this custom code is to use the loginId (unique username from Okta) to lookup additional information about the user within an Oracle database. This additional information cannot be stored on the Okta side. This additional information would have to be available as part of the AuthenticationToken so that it can be retrieved downstream (in the success handler for instance).

My initial attempt was to create a custom AuthenticationProvider (AP), but that proved to be an incorrect approach since targeted placement of my AP was not possible. I then created a custom OidcUserService, however I did not have the ability to extend the Okta implementation because it is declared final. I continued down this path and attempted to add my own more vanilla OidcUserService. Here is the updated http security configure method:

protected void configure(HttpSecurity http) throws Exception
{
    http.authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .oauth2Login()
        .userInfoEndpoint()
        .oidcUserService(new CustomOidcUserService())
        .and()
        .successHandler(customOauthLoginSuccessHandler())
        .failureHandler(customOauthLoginFailureHandler())
        .and()
        .oauth2Client();

    http.csrf().disable();
}

This approach did not work because assignment of the OktaOidcUserService comes after the assignment of my CustomOidcUserService. Mine gets overwritten by the Okta version. I need some advice on how I should approach this problem. How can I inject my own custom code to add additional information to the Authentication object.

I’ve done something very similar with a past SAML implementation and Spring. I was quite easy to integrate my custom flow into the Spring-SAML flow. I created a custom user details class in the case.

Gradle info:

dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
  implementation 'org.springframework.boot:spring-boot-starter-security'
  implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
  implementation 'org.springframework.boot:spring-boot-starter-web'
  implementation 'com.okta.spring:okta-spring-boot-starter:1.2.1'
  developmentOnly 'org.springframework.boot:spring-boot-devtools'
  runtimeOnly 'com.h2database:h2'
  testImplementation 'org.springframework.boot:spring-boot-starter-test'
  testImplementation 'org.springframework.security:spring-security-test'
}

There is a similar item on our backlog: https://github.com/okta/okta-spring-boot/issues/136
Let’s move the conversation over there.

I’ve had a conversation with another user in the same boat and they basically wanted to pull an attribute out of the access token, and then add some custom Authorities to the current user.

Can you comment on that issue with an example of how you will use the data that is added? (I have a few ideas of ways to expose this, I just want to make sure it lines up with your actual usage)

Thanks!