Introduction

For this post, I want to focus on the client interactions with third party oidc providers such as GCP and okta.

Google OAuth2

To set up a simple oidc connection with Google, all we need is to the client id, client secret and the redirect url. The redirect uri is a must due to Google’s protocol requirement. Then we need to configure a SecurityFilterChain bean.

1
2
3
spring.security.oauth2.client.registration.google.client-id=<client_id>
spring.security.oauth2.client.registration.google.client-secret=<client_secret>
spring.security.oauth2.client.registration.google.redirect-uri=http://127.0.0.1:8080/login/oauth2/code/google

Spring security providers some builtin ClientRegistration in the CommonOAuth2Provider.java. For the Google provider,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GOOGLE {
@Override
public Builder getBuilder(String registrationId) {
ClientRegistration.Builder builder = getBuilder(registrationId,
ClientAuthenticationMethod.CLIENT_SECRET_BASIC, DEFAULT_REDIRECT_URL);
builder.scope("openid", "profile", "email");
builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
builder.issuerUri("https://accounts.google.com");
builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
builder.userNameAttributeName(IdTokenClaimNames.SUB);
builder.clientName("Google");
return builder;
}
},

it defines things like default scopes, the authorization endpoint, jwk endpoint etc.

Debug request flow

To debug requests, we first put a breakpoint in FilterChainProxy. It results total of 18 filters, like we discussed in the previous post. The process is basically the same.

  1. We try to access the resource using URL, then encounter an AccessDeniedException.
  2. The exception handler redirect the AccessDeniedException to /login, then send the authorization request to Google’s /auth endpoint.
  3. After successfully authorizing with Google, we create an AuthenticationToken from returned Jwt.

The interesting thing here is that the “email”, “family_name”, “name” values are included as part of the returned Jwt claim set.

Okta OAuth2

To use Okta, it is the same idea. You create the application in auth0.com, configure the redirect-uri, grab the domain, client id, and client secret. The application.properities should like

1
2
3
4
5
6
7
8
9
10
11
12
spring.security.oauth2.client.registration.okta.client-name=okta
spring.security.oauth2.client.registration.okta.client-id=<client_id>
spring.security.oauth2.client.registration.okta.client-secret=<client_secret>
spring.security.oauth2.client.registration.okta.redirect-uri=http://127.0.0.1:8080/login/oauth2/code/okta
spring.security.oauth2.client.registration.okta.scope=openid,profile,email
spring.security.oauth2.client.provider.okta.issuer-uri=<domain>

# if issuer-uri is not specified
# spring.security.oauth2.client.registration.okta.provider=okta
# spring.security.oauth2.client.provider.okta.authorization-uri=<domain>/authorize
# spring.security.oauth2.client.provider.okta.token-uri=<domain>/token
# ...

Observations:

  1. The redirect-uri should include the port if it is local development
  2. If issuer-uri is defined, the OKTA enum from CommonOAuth2Provider.java is not used. In that case, you need to provide the scope.
    Otherwise, if issuer-uri is not define, you have to provide the authorization endpoint, user endpoint, code endpoint etc.
  3. Since Okta support Google login, the “sub” attribute will start with “google-oauth2|” instead of “auth0|”