OIDC Authorization Code Grant Type#
- In the Keycloak Setup, we learned how to set upÂ
Keycloak authorization server forÂOIDC Authorization Code Grant Type . Now, in this section, we will continue to configure the Spring Boot application to be asClientand alsoResource Serverfor connecting to theKeycloakto get token and also verifying in coming token requests with before accessing the data.
Prepare#
- Firstly, we need to review the simple diagram that we are going to do as in the image below.
- The user access
Browserand then call the API/v1/secure/messagesfor getting the protected data. - The
Spring Boot applicationchecks the credential and realize that, the user has not logged in yet then the it will save this APIURLinto a request cache currently the APIURLis stored under aJESSIONIDand it will be used in steps later. Then the user will be responded with a redirect URL to trigger authorization flow. - The
Browsercalls the the responded API for triggering the authorization flow. - When the API
/oauth2/authorization/keycloakis called then theSpring Boot applicationwill prepare an authorization redirect URL and it will also save theOAuth2AuthorizationRequestunder theJESSIONIDon the step above. Then the authorization redirect URL will be responded to the browser. - The
Browserwill redirect to the responded URL to theKeycloak Authorization Serverpage for login with username and password to prove the user identity. - If the username and password are correct then the
Keycloak Authorization Serverwill respond a redirect URL together with anauthorization codeto theBrowser. This redirect URL is theclient registered redirectthat we configured inKeycloak Authorization Serverin Keycloak Setup. - The
Browsercall theclient registered redirectURL together with theAuthorization CodeandJESSIONID - When the
URLis called the filterOAuth2LoginAuthenticationFilterofSpring Boot applicationwill be triggered and it will load theOAuth2AuthorizationRequestwhich is stored in the session to extract some information and repair the request with theauthorization codeand call to theKeycloak Authorization Serverto verify theauhthorization codeand exchange theAccess TokenandID tokenif theauthorization codeis correct. - If the
authorization codeis correct then theAccess Token,ID Tokenand other information will be responded. - The
Spring Boot applicationwill extract those information and build theOAuth2AuthenticationToken. Then thisAuthenticationwill set into a new session and this session will be responded as a newJSESSIONIDcookie. ThisAuthenticationalso be set into theSpring Security Context. Finally, theJESSIONIDcookie with theredirect URLwhich is the first URL that thebrowsercalled/v1/secure/messageswithout the authorization will be responded to the Browser, thisredirect URLis got from the request cache at step 2. - When
Browserreceived theJESSIONIDcookie and redirect URL. Then it will call the redirect URL and theBrowserwill also set theJESSIONIDinto the request automatically. -
The
Spring Boot applicationreceived the request with theJESSIONID(processed in theSecurityContextHolderFilter) and it look up the corresponding session in the session store by the value ofJSESSIONID. If the session exists and theSecurityContextin the session is valid also then theSecurityContextis set in theSecurityContextHolderand finally the data will be response to theBrowser. -
For setting up
Keycloak authorization serverplease view Keycloak Setup with Client Credentials Grant Type.
Spring Boot Server Setup#
Dependencies#
- Let's add some dependencies as below.
| pom.xml | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
- In which for setting up
OIDC Authorization Code Grant Typewith Spring Boot we need the dependencyspring-boot-starter-oauth2-client.
Controller#
- Then let's create 2 simple controllers with 2 simple APIs for testing. One controller is public and the other one is secure controller which need the authentication to access.
| PublicController.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
| SecuredController.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Config#
- Next, let's create a
SecurityConfig.javafor configuring the security as below.
| SecurityConfig.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
-
As you can see that, in this config:
- We just simply disable the csrf by using
http.csrf(AbstractHttpConfigurer::disable). - Then we config public APIs which don't need the authorization by
1 2 3 4 5
.authorizeHttpRequests(auth -> auth.requestMatchers("/v1/public/**") .permitAll() .anyRequest() .authenticated())- Finally, we will configure authentication for OIDC by using
.oauth2Login(withDefaults());
- We just simply disable the csrf by using
-
To use the built-in default
OIDCconfiguration we have to provide some client information in theapplication.yamlas below.
| application.yaml | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
-
So we have the definitions for those configurations as below:
-
Spring Security OAuth2 Client Configuration
- spring.security.oauth2.client.registration.keycloak: Defines the client registration details for Keycloak.
- provider: Specifies the provider for the OAuth2 client, which is Keycloak.
- client-id: The client ID registered with Keycloak.
- client-secret: The client secret associated with the client ID.
- authorization-grant-type: The type of authorization grant to be used, here it is
authorization_code. - scope: The scope of the access request (e.g., openid, profile, email).
- redirect-uri: The URI where the authorization server will redirect to with the authorization code.
- spring.security.oauth2.client.provider.keycloak: Defines the provider details for Keycloak.
- issuer-uri: The issuer URI for the Keycloak realm.
- authorization-uri: The URI to initiate the authorization request.
- token-uri: The URI to obtain the access token.
- user-info-uri: The URI to obtain user information.
- jwk-set-uri: The URI to obtain the JSON Web Key Set (JWKS) for verifying tokens.
- spring.security.oauth2.client.registration.keycloak: Defines the client registration details for Keycloak.
| Configuration | Value | Description |
|---|---|---|
server.port |
7070 |
The port number on which the server runs. |
spring.security.oauth2.client.registration.keycloak.provider |
keycloak |
The OAuth2 provider name. |
spring.security.oauth2.client.registration.keycloak.client-id |
auth-code-grant-type |
The client ID registered with Keycloak. |
spring.security.oauth2.client.registration.keycloak.client-secret |
QXHFcSiFLF96KassAQppb9HJtZ45Lbbf |
The client secret associated with the client ID. |
spring.security.oauth2.client.registration.keycloak.authorization-grant-type |
authorization_code |
The type of authorization grant. |
spring.security.oauth2.client.registration.keycloak.scope |
openid, profile, email |
The scope of the access request. |
spring.security.oauth2.client.registration.keycloak.redirect-uri |
http://localhost:7070/login/oauth2/code/keycloak |
The URI where the authorization server will redirect with the authorization code. |
spring.security.oauth2.client.provider.keycloak.issuer-uri |
http://localhost:8080/auth/realms/myrealm |
The issuer URI for the Keycloak realm. |
spring.security.oauth2.client.provider.keycloak.authorization-uri |
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/auth |
The URI to initiate the authorization request. |
spring.security.oauth2.client.provider.keycloak.token-uri |
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/token |
The URI to obtain the access token. |
spring.security.oauth2.client.provider.keycloak.user-info-uri |
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/userinfo |
The URI to obtain user information. |
spring.security.oauth2.client.provider.keycloak.jwk-set-uri |
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/certs |
The URI to obtain the JSON Web Key Set (JWKS) for verifying tokens. |
Testing#
- Now, let's start the Spring Boot application, open browser and go to
http://localhost:7070/v1/public/messagesthen we can see the message immediately without login.
- Then let's go to
http://localhost:7070/v1/secure/messagesthen you will be navigated to the Keycloak login page for authentication as below.
- Then after login successfully we can see the secure message as below.
Deep Dive Into Details#
- After we testing successfully, now let's open the network and open debug mode for Spring Boot application, and we will check step by step the OIDC Authorization Code Grant Type flow in Spring Security.
- So for the first step, when we access the protected API
http://localhost:7070/v1/secure/messages. Then theSpring Boot applicationchecks the credential and realize that, the user has not logged in yet then the it will save this APIURLinto a request cache, currently the request cache will be stored under aJESSIONID(E6730EA2590274BC5EE3AC11472B29F2) and it will be used in steps later. Then the user will be responded with a redirect URLhttp://localhost:7070/oauth2/authorization/keycloakto trigger authorization flow.
- Now, The
Browsercalls the the responded API for triggering the authorization flow. When the API/oauth2/authorization/keycloakis called then theSpring Boot applicationwill prepare an authorization redirect URL and it will also save theOAuth2AuthorizationRequestinto a session (theJESSIONID-E6730EA2590274BC5EE3AC11472B29F2that we saw in the step above). Then the authorization redirect URL will be responded to the browser. For example:http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/auth?response_type=code&client_id=auth-code-grant-type&scope=openid%20profile%20email&state=Ho4AIPgBfVSA8tykxnsfklRUQo2mRL7cOX5LWe_ex_8%3D&redirect_uri=http://localhost:7070/login/oauth2/code/keycloak&nonce=gugi6sOh-muBFRb9JZFvd0D6Qkmz83MGpEPHk1ESsP4
- The
Browserwill redirect to the responded URL to theKeycloak Authorization Serverpage for login with username and password to prove the user identity.
- After the user click button login then the API in the image above will be called and if the username and password are correct then the
Keycloak Authorization Serverwill respond a redirect URL together with anauthorization codeto theBrowser. This redirect URL is theclient registered redirectthat we configured inKeycloak Authorization Serverin Keycloak Setup.
- The
Browsercall theclient registered redirectURL together with theAuthorization CodeandJESSIONID. When theURLis called the filterOAuth2LoginAuthenticationFilterwhich extends theAbstractAuthenticationProcessingFilterofSpring Boot applicationwill be triggered and it will load theOAuth2AuthorizationRequestwhich is stored in the session to extract some information and repair the request with theauthorization codeand call to theKeycloak Authorization Serverto verify theauhthorization codeand exchange theAccess TokenandID tokenif theauthorization codeis correct. - The method
attemptAuthenticationwill be responsible for extractingOAuth2AuthorizationRequestin theOAuth2LoginAuthenticationFilterand call to theKeyCloakfor getting theAccess TokenandID Token.
| OAuth2LoginAuthenticationFilter.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | |
- We have the code
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository.removeAuthorizationRequest(request, response);is used for getting theOAuth2AuthorizationRequestwhich is stored in the session. It will call the methodremoveAuthorizationRequestunder theHttpSessionOAuth2AuthorizationRequestRepositoryclass. The method will loadOAuth2AuthorizationRequestand remove that attribute in the Session also.
| HttpSessionOAuth2AuthorizationRequestRepository.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
- Go back to the
OAuth2LoginAuthenticationFilterat lineOAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken) this.getAuthenticationManager().authenticate(authenticationRequest);we will call to theKeyCloakProvider to get theAccess TokenandID Token. All these information will be stored in theOAuth2LoginAuthenticationTokenand the Spring Security will extract them to continue the process in the `AbstractAuthenticationProcessingFilter.
- The
Spring Boot applicationwill extractOAuth2LoginAuthenticationTokenand build theOAuth2AuthenticationToken. Then thisOAuth2AuthenticationTokenwill be saved in an attribute of the current Session by supported of theHttpSessionOAuth2AuthorizedClientRepository.
| HttpSessionOAuth2AuthorizedClientRepository.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
- Then this
OAuth2AuthenticationTokenwill be responded to theAbstractAuthenticationProcessingFilter. Then theAbstractAuthenticationProcessingFilterwill set it into a new session and all the session attributes of old session will be copied to it also. This new session will be responded as a newJSESSIONID. See the methoddoFilterinAbstractAuthenticationProcessingFilteras below.
| AbstractAuthenticationProcessingFilter.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
- At line
this.sessionStrategy.onAuthentication(authenticationResult, request, response);in thedoFilterwe will call toCompositeSessionAuthenticationStrategy.javato create a new session and copy all information of old session into it.
| CompositeSessionAuthenticationStrategy.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
- At line
delegate.onAuthentication(authentication, request, response);, theCompositeSessionAuthenticationStrategywill delegate creating and copying information from old session to new session forAbstractSessionFixationProtectionStrategy. See the code below.
| AbstractSessionFixationProtectionStrategy.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
- The line
session = applySessionFixation(request);will call the methodapplySessionFixationofChangeSessionIdAuthenticationStrategywhich will return a new session which contains all information of the old one.
| ChangeSessionIdAuthenticationStrategy.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
- Finally, let's go back to the
AbstractAuthenticationProcessingFilter, the methodsuccessfulAuthentication(request, response, chain, authenticationResult);in methoddoFilterwill be called and theAuthenticationwill be set into theSpring Security Context.
| AbstractAuthenticationProcessingFilter.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
- After that, The line
this.successHandler.onAuthenticationSuccess(request, response, authResult)will trigger the methodonAuthenticationSuccessmethod inSavedRequestAwareAuthenticationSuccessHandlerto continue the process.
| SavedRequestAwareAuthenticationSuccessHandler.java | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
-
In side the method
onAuthenticationSuccessof theSavedRequestAwareAuthenticationSuccessHandler. At lineSavedRequest savedRequest = this.requestCache.getRequest(request, response);, it will load theSavedRequestfrom theHttpSessionRequestCacheand now the new session with copied information from old session from the first step will be loaded. Then the saved request URL will be responded. -
Finally, the new
JESSIONIDcookie together with theredirect URLwhich is the first URL that thebrowsercalled/v1/secure/messageswithout the authorization, thisredirect URLis got from the request cache from firstJESSIONIDwill be responded as in the image above.
- Then now, the browser will call the
redirect URLand it will add the newJESSIONIDautomatically and we can get the secure message successfully.










