OpenID Connect Client with Spring Security

OpenID Connect Client with Spring Security

On this page

One of the key features of Spring Security 5 was the native support for OAuth2 and OIDC. Making use of the OIDC configuration information (OIDC metadata), integrating with the Curity Identity Server gets super easy. This tutorial shows how to use a registered OAuth client to login via Curity Identity Server and access the user details within an ID-token.

Note

This example is based on the Curity Identity Server, but any server that supports OIDC flows would do.

This tutorial illustrates two different ways for client authentication:

  • Basic authentication with a client ID and client secret
  • JWT client assertion with a client ID and client key pair

Prerequisites

Make sure you configure a client in the Curity Identity Server before getting started. You must be familiar with the following details:

  • Client Id
  • Client Secret
  • Scopes
  • Authorization Grant Type (Capability)
  • Redirect URI

Commonly, the authorization server provides you with the client ID and secret as well as the supported scopes for the client. This tutorial runs a client with the Code Flow. Spring Boot generates the redirect URI automatically with the form {baseUrl}/login/oauth2/code/{registrationId}.

In this example, the application is deployed locally and the following values apply:

Parameter NameValue in Tutorial
Client IDdemo-basic-client
Client SecretSecr3t
Scopesopenid, profile
Authorization Grant Typeauthorization_code
Redirect Urihttp://localhost:8080/login/oauth2/code/demo-basic-client
Provideridsvr

To configure a new client using basic authentication follow the tutorial here: Setup a Client.

Instead of creating the client manually you can merge the following XML with your current configuration.

xml
1234567891011121314151617181920212223242526272829
<config xmlns="http://tail-f.com/ns/config/1.0">
<profiles xmlns="https://curity.se/ns/conf/base">
<profile>
<id>token-service</id>
<type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type>
<settings>
<authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
<client-store>
<config-backed>
<client>
<id>demo-basic-client</id>
<secret>Secr3t</secret>
<redirect-uris>http://localhost:8080/login/oauth2/code/demo-basic-client</redirect-uris>
<scope>openid</scope>
<scope>profile</scope>
<user-authentication>
</user-authentication>
<capabilities>
<code/>
</capabilities>
<validate-port-on-loopback-interfaces>true</validate-port-on-loopback-interfaces>
</client>
</config-backed>
</client-store>
</authorization-server>
</settings>
</profile>
</profiles>
</config>

For this tutorial the OpenID Connect metadata of the Curity Identity Server must be published. Spring Boot makes use of the location of the OpenID Connect Provider to load the essential configuration for the integration. In this way you do not have to keep track of all the endpoints. The Curity Identity Server publishes the metadata at {issuerUri}/.well-known/openid-configuration and the value for the issuer URI in this tutorial is as follows:

Parameter NameValue in Tutorial
OpenID Provider Issuer Urihttps://idsvr.example.com/oauth/v2/oauth-anonymous

Create a Spring Boot Application

Use the Spring Initializr to create a simple Spring Boot application from scratch. It is a website that assists you to create a new Spring Boot application with the necessary dependencies.

Open start.spring.io in your browser to access Spring Initializr.

In the configuration window that opens, enter io.curity.example for the name of the group and call the artifact demo-client.

Search for and add the following dependencies:

  • Spring Security
  • OAuth2 Client
  • Spring Reactive Web
  • Thymeleaf

Spring Initializr

Generate the application. Spring Initializr creates an archive with a bootstrap application that includes the selected dependencies. Download and extract the archive, and import the project in an IDE of your choice.

Add a Starting Site

Provide a starting site that is publicly available. Create the file src/main/resources/templates/index.html. Add a link to the protected resource /user.

html
123456789101112
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spring Boot OIDC Demo</title>
</head>
<body>
<h1>Welcome</h1>
<p>Show me my <a href="/user">user name</a></p>
</body>
</html>

Add a Controller

When the user logs in show the username. For that create a controller that handles requests for the endpoint / and /user. Create the file src/java/main/io/curity/example/oidcClient/UserController.java:

java
123456789101112131415
@Controller
public class UserController {
@GetMapping("/")
public String index(){
return "index";
}
@GetMapping("/user")
public String user(Model model,
@AuthenticationPrincipal OidcUser oidcUser) {
model.addAttribute("userName", oidcUser.getName());
model.addAttribute("audience", oidcUser.getAudience());
return "user";
}
}

For demonstration purpose, print out the application that triggered the login.

Create a template called user.html next to index.html. Output the attributes for the username and client ID.

html
123456789101112131415
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Spring Boot OIDC Demo - Login</title>
<meta charset="utf-8" />
</head>
<body>
<h1>Your Login Details</h1>
<div>
Welcome <span style="font-weight:bold" th:text="${userName}"/>!
You logged in at the OAuth 2.0 Client <span style="font-weight:bold" th:text="${audience}"/>.
</div>
</body>
</html>

Protect the User Area

So far there are two endpoints: / and /user. However, both are still unprotected. Create another class, that enforces OAuth for certain paths. Create the file src/java/main/io/curity/example/democlient/OAuth2SecurityConfig.java with the following content:

java
1234567891011121314
@Configuration
public class OAuth2SecurityConfig {
@Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges ->
exchanges
.pathMatchers("/", "/error").permitAll()
.anyExchange().authenticated()
)
.oauth2Login(withDefaults());
return http.build();
}
}

This enables and configures Spring Web Security. The endpoints / and /error are public. Any other requests must be authenticated using OAuth. Spring Security creates a default login page at /login that lists all the login options. When running the example from GitHub, there are two options:

  • Login with the Curity Identity Server (Basic Client)
  • Login with the Curity Identity Server (Private JWT Client)

Configure the OAuth Client

Define the following client in src/main/resources/application.yml:

yaml
12345678910111213141516
spring:
security:
oauth2:
client:
registration:
demo-basic-client:
client-name: Login with the Curity Identity Server (Basic Client)
client-id: demo-basic-client
client-secret: Secr3t
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
scope: openid, profile
provider: idsvr
provider:
idsvr:
issuer-uri: https://idsvr.example.com/oauth/v2/oauth-anonymous

This triggers Spring Boot to register a client. The client registration gets the id demo-basic-client which is part of the (default) redirect-uri.

The remaining properties, client-id, client-secret, authorization-grant-type and scope, have been defined when configuring the client in the Curity Identity Server (see Prerequisites). You can choose any descriptive client-name. This is the string that is used in the default login page setup at /login.

Spring Boot Security loads all the necessary OpenID configuration from the metadata at https://idsvr.example.com/oauth/v2/oauth-anonymous/.well-known/openid-configuration and ensures that the user-agent gets redirected to the right endpoints for authentication.

Run the Demo Application

Start the demo application with ./gradlew bootRun

Navigate to http://localhost:8080 to access the index site.

Index

Click on the link to access http://localhost:8080/user that triggers a login.

Login

After successful login the page shows details retrieved from the ID token.

User

You can also navigate to http://localhost:8080/login to directly access the default login page created by Spring Security.

Conclusion

Using Spring Security together with the Curity Identity Server you can easily secure your application with OAuth2 and OpenID Connect. As a developer you only have to add a client registration using the parameters received from an administrator of the Curity Identity Server and enable OAuth2 support for your application. You can access any attributes in the ID token through @AuthenticationPrincipal and OidcUser.class or use @RegisteredOAuth2AuthorizedClient and OAuth2AuthorizedClient.class for retrieving the access token obtained by the client that you may forward to downstream APIs.

For further examples and help regarding OAuth2 and Spring Security for a reactive web application visit Spring Security Reference Documentation.

Also check out the tutorial on mutual TLS client authentication using Spring Boot: OIDC Client with Mutual TLS Client Authentication