This project is an example implementation of a OpenID Connect Relying Party built using Spring Boot and Spring Security OAuth2 Client.
Keycloak is used as the public Identity Provider for testing purposes
The Spring Boot application exposes its JWKS at http://localhost:8081/oauth2/jwks
Start Keycloak
kc start-devAccess Keycloak at http://localhost:8080/
- Create an administrative user
 - Login to the administrative console
 - Create the 
testrealm- Click on the 
Keycloakdropdown on the left navigation bar - Select 
Create Realm - Set 
testas theRealm nameand click onCreate 
 - Click on the 
 - Create the 
keycloak-spring-boot-exampleclient- Click on 
Clientson the left navigation bar - Click on 
Create client - Set 
keycloak-spring-boot-exampleas theClient IDand click onNext - Toggle 
Client authenticationtoOnand click onNext - Set 
http://localhost:8081/*asValid redirect URIs,Valid post logout redirect URIsandWeb originsand click onSave - Under 
Logout settings- Toggle 
Front channel logouttoOff - Set 
http://localhost:8081/logout/connect/back-channel/keycloakasBackchannel logout URLand click onSave 
 - Toggle 
 - Click on 
Credentials - Click on the 
Client Authenticatordropdown and selectSigned Jwtand click onSave - Click on 
Keys - Toggle 
Use JWKS URLtoOnand enterhttp://localhost:8081/oauth2/jwksas theJWKS URLand click onSave 
 - Click on 
 - Allow user registrations
- Click on 
Realm settingson the left navigation bar - Click on 
Login - Toggle 
User registrationtoOn 
 - Click on 
 
mvn spring-boot:run| Description | Endpoint | 
|---|---|
| Access the application | http://localhost:8081/login-user | 
| Logout from the application | http://localhost:8081/logout | 
| View the public keys | http://localhost:8081/oauth2/jwks | 
| Access Keycloak user account | http://localhost:8080/realms/test/account | 
| Logout from Keycloak | http://localhost:8080/realms/test/protocol/openid-connect/logout | 
Note that this example does not securely store the private keys which are located in src/main/resources/jwks.json. This should be securely stored and rotated, for instance on AWS this should be stored in AWS Secrets Manager with a Secrets Manager Rotation Lambda. This can be configured in Spring using Spring Cloud AWS Secrets Manager.
Keycloak will call the endpoint http://localhost:8080/oauth2/jwks in order to get the public keys of the application
- The public verification key used for Keycloak to verify the signature for the 
private_key_jwtclient assertion 
The JWKSet @Bean used by the application is produced in WebSecurityConfiguration and its public keys are exposed using the @RestController JwksController. Note that JWKSet.toString() removes the private components of the keys.
Keycloak was configured to use private_key_jwt client authentication by setting Signed Jwt as the Client Authenticator.
Spring needs to be configured to use this client authentication method, and the token response client needs to be configured to use the appropriate private key to perform the signing.
spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: keycloak-spring-boot-example
            client-authentication-method: private_key_jwt
            authorization-grant-type: authorization_code
            scope:
            - openidThe DefaultAuthorizationCodeTokenResponseClient is used with the NimbusJwtClientAuthenticationParametersConverter configured with the private key and NimbusJwtClientAuthenticationParametersConverter used to customize the claims and headers on the client assertion.
Spring supports the use of the end_session_endpoint to inform Keycloak that the user is being logged out. This is done by configuring a OidcClientInitiatedLogoutSuccessHandler as the logout success handler. Upon logout success this will redirect the browser to the end_session_endpoint with the id_token_hint set. Keycloak will then redirect the browser back to the application using the post_logout_redirect_uri.
Spring supports receiving back channel logout requests from Keycloak if the user logs out from Keycloak.
http.oidcLogout(oidcLogout -> oidcLogout.backChannel(withDefaults()));The client on Keycloak needs to be configured to
- Toggle 
Front channel logouttoOff - Set 
http://localhost:8081/logout/connect/back-channel/keycloakasBackchannel logout URL 
Where keycloak corresponds to the client registration id.
sequenceDiagram
    autonumber
    participant User
    participant Browser
    participant Application Server
    participant Keycloak
    User->>Browser: Navigate to user information page
    Browser->>Application Server: Send request for user information page (/login-user)
    Application Server->>Application Server: Not authenticated, determine provider to redirect to
    Application Server-->>Browser: Redirect to Application for Keycloak provider
    Browser->>Application Server: Send request for Keycloak provider (/oauth2/authorization/keycloak)
    Application Server->>Application Server: Generate Authorization Request
    Application Server-->>Browser: Redirect to Keycloak with Authorization Request
    Browser->>Keycloak: Send Authorization Request (/realms/test/protocol/openid-connect/auth)
    Keycloak->>Keycloak: Generate login page
    Keycloak-->>Browser: Return login page
    User->>Browser: Enter login credentials and sign in
    Browser->>Keycloak: Send login credentials 
    Keycloak->>Keycloak: Process login credentials
    Keycloak-->>Browser: Redirect to Application with Authorization Response with code
    Browser->>Application Server: Send Authorization Response with code (/login/oauth2/code/keycloak)
    Application Server->>Application Server: Generate Token Request and client credentials
    Application Server->>Keycloak: Send Token Request with client credentials (/realms/test/protocol/openid-connect/token)
    Keycloak->>Application Server: Send request for client json web key set (/oauth2/jwks)
    Application Server-->>Keycloak: Return client json web key set
    Keycloak->>Keycloak: Process client credentials and create tokens
    Keycloak-->>Application Server: Return Token Response with access, refresh and id tokens
    Application Server-->>Browser: Redirect to user information page
    Browser->>Application Server: Send request for user information page (/login-user)
    Application Server->>Application Server: Authenticated
    Application Server-->>Browser: Return user information page