DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Secure Your API With JWT: Kong OpenID Connect
  • Securing REST APIs With Nest.js: A Step-by-Step Guide
  • Navigating the API Seas: A Product Manager's Guide to Authentication
  • Spring OAuth Server: Token Claim Customization

Trending

  • Kafka and Spark Structured Streaming in Enterprise: The Patterns That Hold Up Under Pressure
  • You Don't Get to Retrofit Trust: Why API Security Must Be Designed In, Not Bolted On
  • Observability in Spring Boot 4
  • What Nobody Tells You About Multimodal Data Pipelines for AI Training
  1. DZone
  2. Software Design and Architecture
  3. Security
  4. Spring OAuth Server: Default Configuration

Spring OAuth Server: Default Configuration

Explore Spring Authorization server's default configuration: registration of new clients, testing endpoints, JWT customization, and reference/self-contained tokens.

By 
Naveen Maanju user avatar
Naveen Maanju
·
Nov. 10, 23 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
7.2K Views

Join the DZone community and get the full member experience.

Join For Free

Spring has come out with an OAuth2 solution, and in this article, we will look at the default configuration that comes bundled with the spring-oauth server. Details about how OAuth2.0 works are out of the scope of this article and the audience of this article is expected to have a basic understanding of it. You can find more details on it here.

In this and other articles, I will talk more about the technical aspects of the Spring OAuth2.0 solution.

Default Configuration

Spring OAuth server comes with some default settings. One can customize it by configuring the server/clients in the application.yml config file. The following flows (grant types) are supported:

  1. Client Credentials flow (/oauth2/token endpoint)
  2. Authorization Code flow (Including PKCE)
  3. Resource Owner Credential Flow (Deprecated)
  4. Implicit flow (Code flow without code :))
  5. Device Authorization flow

Details around the configuration can be found at the GitHub. This is a sample codebase. 

Regarding default configuration, you can refer to the server configuration here where we can see how configuration can be done to use the default server configuration.

AuthorizationServerTest can be referred to see how we can verify different endpoints through functional testing. To make this test run successfully, the OAuth server should be running. To run the server, you can use the AuthorizationServerApplication class using IDE or from the command prompt as well using the command below:

Shell
 
mvn spring-boot:run


Let's look at the sample client "spring" (you can name it anything you want to) configuration and talk about the significance of each property below.

YAML
 
spring:
  security:
    oauth2:
      authorizationserver:
        client:
          spring:
            registration:
              client-id: "spring-test" #The name to be used in different configurations to refer this client. 
              client-secret: "sMJ1ltm5wxdcOeEJGaE6WdFj9ArR75wkBqUgVE7vwwo="  ##Using D3PasswordEncoder
              client-authentication-methods: #methods supported to authenticate the client
                - "client_secret_basic"
                - "client_secret_post"
              authorization-grant-types: #The flows this client support
                - "authorization_code"
                - "refresh_token"
                - "client_credentials"
              redirect-uris:  # The Url to be used at the end of successful authentication 
                - "https://127.0.0.1:9443/"
                - "https://127.0.0.1:9443/login/oauth2/code/spring"
              post-logout-redirect-uris:
                - "http://127.0.0.1:8080/"
              scopes:
                - "openid"
                - "profile"
                - "email"
            require-authorization-consent: true


  • client-id: A unique ID assigned to the client; it will be used to identify the client and configuration whenever the client makes a call to the authorization server.
  • client-secret: Secret to be used by the client to authenticate itself when making a call to the authorization server
  • client-authentication-methods: Authentication methods that the client uses to authenticate itself
    • client_secret_basic: Basic authentication approach where credentials are provided as headers (httpHeaders -> httpHeaders.setBasicAuth(TEST_CLIENT_ID, TEST_SECRET))
    • client_secret_post: Authentication by providing credentials in the request body (application/x-www-form-urlencoded)
  • authorization-grant-types: The grant types supported by the client
  • redirect-uris: The redirect-uri(s) that is/are supported by the client and allow redirects that the client can use while starting the authorize_code flow
  • post-logout-redirect-uris:  redirect-uri(s) after successful logout from openId
  • scopes: Supported scopes by the client
  • require-authorization-consent: If consent is required during the authorization code flow

Some of the default configurations that are good to know and not there by default in different examples are:

  1. Access token format by default is self-contained (jwt) and can be configured to opaque (reference) token through configuration.
  2. The refresh token TTL is 60min.
  3. The access token TTL is 5min.
  4. The authorization code TTL is 5min.
  5. The consent form is disabled by default.

We can override the above default behavior by overriding the configuration in the application.yml file as:

YAML
 
spring:
  security:
    oauth2:
      authorizationserver:
        client:
          spring-client:
            require-authorization-consent: true
            token:
              access-token-format: reference
              authorization-code-time-to-live: PT10M
              access-token-time-to-live: PT10M
              refresh-token-time-to-live: PT2H


Default Security FilterChain

Sometimes I think about how the security framework is configured to make it work, so here is what I tried to put together on how the application is configured using different configurations, filters, and properties to make it work.

Starting With Application FilterChain

Filters(5):

  1. ApplicationFilterConfig (characterEncodingFilter)
  2. ApplicationFilterConfig (formContentFilter)
  3. ApplicationFilterConfig (requestContextFilter)
  4. ApplicationFilterConfig (springSecurityFilterChain)
  5. ApplicationFilterConfig (Tomcat WebsocketFilter-JSR356)

ApplicationFilterConfig (springSecurityFilterChain)

Application filter config "springSecurityFilterChain" is the main class that holds the filter (Spring Security) instances which are instantiated when a web application is started.

The filter instance it (springSecurityFilterChain-ApplicationFilterConfig) holds is DelegatingFilterProxyRegistrationBean. DelegatingFilterProxyRegistrationBean is a ServletContextInitializer; it registers DelegatingFilterProxy and holds the name of the actual delegate.

Filter (DelegatingFilterProxyRegistrationBean) [springSecurityFilterChain urls=[/*] order=-100]:

Java
 
public class DelegatingFilterProxyRegistrationBean
extends AbstractFilterRegistrationBean<DelegatingFilterProxy>
implements ApplicationContextAware


  • TargetBeanName: springSecurityFilterChain 
  • Filter (DelegatingFilterProxy)

DelegatingFilterProxy

Spring provided filter implementation, a bridge between the servlet container and Spring's ApplicationContext.

  • TargetBeanName: springSecurityFilterChain
  • Delegate: FilterChainProxy 

FilterChainProxy

This holds the Spring Security filter chain(s). Concerning the OAuth authorization server, there are two security filter chains (DefaultSecurityFilterChain): one for the OAuth endpoint and one for the rest.

  • FilterChains: An overview of the oauth2filter chain
    • DefaultSecurityFilterChain (OAuth2 endpoints)
    • RequestMatcher (OAuth2AuthorizationServerConfigurer)
Plain Text
 
Or [
  OAuth2ClientuthenticationConfigurer
  Or [ 
     Ant [pattern='/oauth2/token', POST], 
     Ant [pattern='/oauth2/introspect', POST], 
     Ant [pattern='/oauth2/revoke', POST], 
     Ant [pattern='/oauth2/device_authorization', POST]
     ], 
  OAuth2AuthorizationServerMetadataEndpointConfigurer
    Ant [pattern='/.well-known/oauth-authorization-server', GET], 
  OAuth2AuthorizationEndpointConfigurer
  Or [
    Ant [pattern='/oauth2/authorize', GET], 
    Ant [pattern='/oauth2/authorize', POST]
    ], 
  OAuth2TokenEndpointConfigurer
  Ant [pattern='/oauth2/token', POST], 
  OAuth2TokenIntrospectionEndpointConfigurer
  Ant [pattern='/oauth2/introspect', POST], 
  OAuth2TokenRevocationEndpointConfigurer
  Ant [pattern='/oauth2/revoke', POST], 
  OAuth2DeviceAuthorizationEndpointConfigurer
  Ant [pattern='/oauth2/device_authorization', POST], 
  OAuth2DeviceVerificationEndpointConfigurer
  Or [
      Ant [pattern='/oauth2/device_verification', GET], 
      Ant [pattern='/oauth2/device_verification', POST]
    ], 
  OidcConfigurer
  Or [
     OidcProviderConfigurationEndpointConfigurer
     Ant [pattern='/.well-known/openid-configuration', GET], 
     OidcLogoutEndpointConfigurer
     Or [
         Ant [pattern='/connect/logout', GET], 
         Ant [pattern='/connect/logout', POST]
        ], 
    OidcUserInfoEndpointConfigurer
    Or [
        Ant [pattern='/userinfo', GET], 
        Ant [pattern='/userinfo', POST]]
      ], 
    NimbusJwkSetEndpointFilter
    Ant [pattern='/oauth2/jwks', GET]
  ]


  • Filters (25)
Plain Text
 
0 = {DisableEncodeUrlFilter} 
1 = {WebAsyncManagerIntegrationFilter} 
2 = {SecurityContextHolderFilter} 
3 = {AuthorizationServerContextFilter} 
4 = {HeaderWriterFilter} 
5 = {CsrfFilter} 
6 = {OidcLogoutEndpointFilter} 
7 = {LogoutFilter} 
8 = {OAuth2AuthorizationServerMetadataEndpointFilter} 
9 = {OAuth2AuthorizationEndpointFilter} 
10 = {OAuth2DeviceVerificationEndpointFilter} 
11 = {OidcProviderConfigurationEndpointFilter} 
12 = {NimbusJwkSetEndpointFilter} 
13 = {OAuth2ClientAuthenticationFilter} 
14 = {BearerTokenAuthenticationFilter} 
15 = {RequestCacheAwareFilter} 
16 = {SecurityContextHolderAwareRequestFilter} 
17 = {AnonymousAuthenticationFilter} 
18 = {ExceptionTranslationFilter} 
19 = {AuthorizationFilter} 
20 = {OAuth2TokenEndpointFilter} 
21 = {OAuth2TokenIntrospectionEndpointFilter} 
22 = {OAuth2TokenRevocationEndpointFilter} 
23 = {OAuth2DeviceAuthorizationEndpointFilter} 
24 = {OidcUserInfoEndpointFilter} 


  • DefaultSecurityFilterChain (other endpoints)
    • RequestMatcher (AnyRequestMatcher)
    • Filters (14)
Plain Text
 
0 = {DisableEncodeUrlFilter@8893} 
1 = {WebAsyncManagerIntegrationFilter@8894} 
2 = {SecurityContextHolderFilter@8895} 
3 = {HeaderWriterFilter@8896} 
4 = {CsrfFilter@8897} 
5 = {LogoutFilter@8898} 
6 = {UsernamePasswordAuthenticationFilter@8899} 
7 = {DefaultLoginPageGeneratingFilter@8900} 
8 = {DefaultLogoutPageGeneratingFilter@8901} 
9 = {RequestCacheAwareFilter@8902} 
10 = {SecurityContextHolderAwareRequestFilter@8903} 
11 = {AnonymousAuthenticationFilter@8904} 
12 = {ExceptionTranslationFilter@8905} 
13 = {AuthorizationFilter@8906} 


Default Response

Token Endpoint

By default, the token response for the /oauth2/token endpoint will be:

JSON
 
{
   "access_token":"eyJraWQiOiJiOTM0NjIyMy00ZWJiLTQyZjItYTAyYy1hNDlkNDQwOWRlMjEiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjYwNjAiLCJzdWIiOiJzcHJpbmctdGVzdCIsImF1ZCI6InNwcmluZy10ZXN0IiwibmJmIjoxNjk3MTgzODU2LCJleHAiOjE2OTcxODQxNTYsImlhdCI6MTY5NzE4Mzg1Nn0.KzYvm4YAuLRvpF9eco-z1ESbYU-MCChvxbdEPuGgQN-8seco8MgLWWoGM4dbbMRBJLe3Rv3YAEGhJ9qqenNtpFmVnysAUFqw_S8GEUpPlXzzRTnV_qoeqY9YVazCn9TonJJkjzj_RATTHgDx4TD6ZXSP963L5fwNjLtQ2Cp_yoi5R8WDgMkpvOubmuhjAxYpRH7rBH3qzNWo3vqRPuWreeoyaRyK-9HNOTKxT3vj7aLkTK1wyxzfPxliXXXMJ4IsxjxUOTfzzfHF9qmOYZCoCCgVtNlopsSKmjJKRID8UVugzmYQx1pZkUSPMOxiz1AloEX1-6DhgoC3lMi0-Ez6pQ",
   "token_type":"Bearer",
   "expires_in":299
}


If you parse the access_token using https://jwt.io/, you can view the claims issued in the token. The default set of claims are:

JSON
 
{
  "iss": "http://localhost:6060",
  "sub": "spring-test",
  "aud": "spring-test",
  "nbf": 1697183856,
  "exp": 1697184156,
  "iat": 1697183856
}


Metadata Endpoints

1. http://localhost:6060/.well-known/oauth-authorization-server

2. http://localhost:6060/.well-known/openid-configuration

Metadata endpoints provide the details around the authorization-server and openId current configuration and endpoints exposed. 

Code Flow Token response (/oauth2/token)

JSON
 
{
   "access_token":"eyJraWQiOiI4M2ZiMmRhYy1hZGNlLTRkNzgtODlhYy0wOGQzM2U3OGRmNGMiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMSIsImF1ZCI6InNwcmluZy10ZXN0IiwibmJmIjoxNjk4MTUxODMzLCJzY29wZSI6WyJvcGVuaWQiLCJwcm9maWxlIl0sImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjA2MCIsImV4cCI6MTY5ODE1MjEzMywiaWF0IjoxNjk4MTUxODMzfQ.jbNg1MyrL-9kHpfhhkarNfSq1VuS3fPJUZyXjSaliuaziKZzSrma2OyUtVrrPJYzv7FMk-pGrTZVJLZ8f6Jayq2IbHkuWl2XYexRRQmUUDSeC3WMxDhWqezqRc-AEyrTQXm2d0HNs0zdJX9H28bSpGg_SADuKuN-vLuFp3_5w2utveuYxq1e2Ts-IXE-9ulf9O19Mj0Wf9hgENTOZiKbqUWvvoZwXhsx4LzPXqGKM0MbZTS6kFpdSZIgzcbaPzcMX_Vq_B2AU9_UAlJua2Vzxh-9rdJ7SPDVxT-ezoUGp61c1s5eDop2zNszjDqd7kE4qepCiJy6bUuwvP7yewdreg",
   "refresh_token":"ARM4_nA8LFzFajbTOzJjN1OTGByZAFu9HGoDeZ9mfciY9vEv5XbWc7MuzcQnAArZMMnB_ydsCxsLRC4HY4u0oh9DscHySysYPXb1BE-7JBwcdH_hVKM3pXWmO4NEiDY",
   "scope":"openid profile",
   "id_token":"eyJraWQiOiI4M2ZiMmRhYy1hZGNlLTRkNzgtODlhYy0wOGQzM2U3OGRmNGMiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2VyMSIsImF1ZCI6InNwcmluZy10ZXN0IiwiYXpwIjoic3ByaW5nLXRlc3QiLCJhdXRoX3RpbWUiOjE2OTgxNTE4MzMsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjA2MCIsImV4cCI6MTY5ODE1MzYzMywiaWF0IjoxNjk4MTUxODMzLCJzaWQiOiJfVmYzY1ZTREd1UDQtMEN6czNzR1BxQTZkaUk1ZjB1TE1pT1BkUzd3Z0c4In0.QDHOUa2p8RZKHVuhnHUsvMX-HmEvsGXXQ6QgfidXEMO0vDxJilmYIWW90z9Etc2cJ1SjfFk4OrUZWQF2foa2secatuAeffTbUx_9lTPD4KT_xzg9SsP69tHt55J2U35FcFef2WHuGF06MOj2hr6dVqlk8B5ORV0z_XiBM9FBEmnraLvXWtXtlwp_-jGA95O7y2U8SZt9H8wns-IpatXshB8lnUk-P5NjV8-CUwqtb9FHKOr9ie4KSXHQ8IpY2FaBMI0nA4E_hCUV2xpP_nBAb7Prh5EDYoCFkjHtO5ZXe-VYhyff9AydPzFsdSmEeF6BEK6SeJPBXRUvtL_bZykjdA",
   "token_type":"Bearer",
   "expires_in":299
}


In the code flow at the end of the flow when code is issued to the client at redirect_uri, the backend service will collect the code and call the token endpoint /oauth2/token.

Introspection Response When the Token Is Active

JSON
 
{
	"active": true,
	"client_id": "spring-test",
	"iat": 1698151833,
	"exp": 1698155433
}


Introspection Response Post Revoke

JSON
 
{
	"active": false,
	"iat": 0,
	"exp": 0
}


I hope you found this article informative. I will put more details in another post on how to customize the token response by adding new claims to JWT.

Integrated development environment authentication JWT (JSON Web Token) security

Opinions expressed by DZone contributors are their own.

Related

  • Secure Your API With JWT: Kong OpenID Connect
  • Securing REST APIs With Nest.js: A Step-by-Step Guide
  • Navigating the API Seas: A Product Manager's Guide to Authentication
  • Spring OAuth Server: Token Claim Customization

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook