OIDC Client with Spring Security

OIDC Client with Spring Security

tutorials

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.

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 authentication and client secret
  • scopes
  • authorization grant type (capability)
  • redirect uri

To configure a new client follow the tutorial here: Setup a Client

We assume that the application will be deployed locally which is reflected in the redirect uri. We will use the following values:

Parameter NameValue in tutorial
Client IDdemo-client
Client SecretSecr3t
Scopesopenid, profile
Authorization Grant Typecode
Redirect Urihttp://localhost:8080/login/oauth2/code/idsvr

Instead of creating the client manually you can merge the following xml with your current configuration. Before committing the change, configure the client to authenticate with the secret from the table above.

<config xmlns="http://tail-f.com/ns/config/1.0">
  <profiles xmlns="https://curity.se/ns/conf/base">
  <profile>
    <id>my-oauth-profile</id> <!-- Replace with the ID of your OAuth profile -->
    <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-client</id>
        <client-name>Spring Boot Demo</client-name>
        <redirect-uris>http://localhost:8080/login/oauth2/code/idsvr</redirect-uris>
        <scope>openid</scope>
        <scope>profile</scope>
        <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. We will make use 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 Provider publishes the metadata at {issuerUri}/.well-known/openid-configuration. We define the issuer uri as follows:

Parameter NameValue in tutorial
OpenID Provider Issuer Urihttps://idsvr.example.com/oauth/anonymous

Using the OpenID Connect metadata is not only for convenience but also because some configuration data will only be available this way and cannot be configured otherwise using Spring Boot. See Spring Security Reference.

Create a Spring Boot Application

We will create a simple Spring Boot application from scratch using Spring Initializr, a website helping 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.

Use HTTPS

It is good practice to secure web applications with HTTPS. Therefore we explain quickly how you can configure SSL for this Spring Boot application.

Run the following command to create a self-signed certificate for localhost:

keytool -genkeypair -alias https -keyalg RSA -keysize 4096 -keystore server.p12 -storepass Secr3t -storetype pkcs12 -validity 10 -dname "CN=localhost, OU=Example, O=Curity AB, C=SE"

Copy the file server.p12 into src/main/resources. Rename application.properties in the same folder to application.yml and configure HTTPS for the application by adding the following fragment to the file:

server:
  port: 9443
  ssl:
    key-store: classpath:server.p12
    key-store-password: Secr3t
    key-store-type: pkcs12
    key-store-alias: https

The application will now run on https://localhost:9443.

Insecure Certificate

The browser will not trust this self-signed server certificate. You may notice an `SSLHandshakeException` in the console when running this example. Make sure your browser trusts the certificate if you want to get rid of the error.

Add a Starting Site

We will have a starting site that will be publicly available. Create the file src/main/resources/templates/index.html. Add a link to the protected resource /user.

<!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 we want to show the user name. For that we need a controller that handles requests for the endpoint / and /user. Create the file src/java/main/io/curity/example/oidcClient/UserController.java:

@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, we will also print out the application that triggered the login.

Create a template called user.html next to index.html. Output the attributes for the user name and client-id.

<!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 we have two resources: / and /user. However, we did not apply any security yet. We need another class, that requires OAuth for certain paths. Create the file src/java/main/io/curity/example/democlient/OAuth2SecurityConfig.java with the following content:

@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 will create a default login page at /login that lists all the login options. In our case there will be just one option Login with the Curity Identity Server.

Configure the OAuth Client

Rename the src/main/resources/application.properties to application.yml. Register the following client:

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

This triggers String Boot to register a client. The client registration gets the id idsvr that is also 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 client-name. This is the string that will be used in the default login page setup at /login.

Spring Boot Security will load all the necessary OpenID configuration from the metadata at https://idsvr.example.com/oauth/v2/oauth-anonymous/.well-known/openid-configuration and ensure that the User-Agent will get redirected to the right endpoints for authentication.

Run the Demo Application

Start the demo application with mvn spring-boot:run

Navigate to https://localhost:9443 to access the index site.

Index

Access https://localhost:9443/user to trigger a login.

Login
After successful login you will be presented with details retrieved from the ID token.

User

You can also navigate to https://localhost:9443/login to access the default login page created by Spring Security.

Conclusion

Using Spring Security 5 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.

Further Information and Source Code

You can find the source code of the example on GitHub.

For further examples and help regarding OAuth2 and Spring Security visit Spring Security Reference.

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

Let’s Stay in Touch!

Get the latest on identity management, API Security and authentication straight to your inbox.

Keep up with our latest articles and how-tos using RSS feeds