OAuth 2.0 is the industry-standard protocol for authorization or to be precise a specification for issuing access tokens defined in RFC 6749. It focuses on client developer simplicity while providing specific authorization flows for different kinds of applications.
For a detail description of the different OAuth 2.0 flows, I recommend reading through this post.

Problem Description

The configuration of OAuth consists of some OAuth provider-specific server configuration (server endpoints) and a client configuration (clientID, secret, accessTokenUri, scope…). Both parts of the OAuth configuration are usually configurated statically in a standard Spring Boot Application.

During my career, I faced some requirements to configure OAuth dynamically.

  • Per request (context) specific clientIDs, accessTokenUris, …
  • Loading the configuration from an external service at runtime
  • Handling legacy OAuth provider during the changeover period

According to my knowledge, the OAuth 2.0 standard does not expose any endpoints dynamically offering information about the client or server configuration. Therefore, dynamic OAuth configurations on the client-side seem quite uncommon. Especially in Spring Boot Applications static OAuth configuration using application properties are widespread.
Alternatively, Spring Security offers a so-called dynamic approach using a database that contains different configurations that can be loaded by clientID. Well, in my point of view this approach is very limiting and does not represent a real dynamic OAuth client configuration approach.

In contrast, OpenID Connect is a widespread OAuth extension that offers a dynamic client configuration option as well as an OAuth provider discovery endpoint (/issuerURL/.well-known/openid-configuration).

Solution

Fortunately, the static Spring OAuth client configuration implementation can be adjusted easily. The simple OAuth client example described by the documentation consists of some static OAuth client properties which are mapped to the AuthorizationCodeResourceDetails.class at startup time.

oauth:
  client:
    clientId: 233668646673605
    clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
    accessTokenUri: https://domain.com/oauth/access_token
    userAuthorizationUri: https://domain.com/dialog/oauth
    ...
@Bean
@ConfigurationProperties("oauth.client")
public AuthorizationCodeResourceDetails client() {
    return new AuthorizationCodeResourceDetails();
}

In order to extend the static configuration of OAuth properties into a dynamic configuration, the AuthorizationCodeResourceDetails.class needs to be adjusted to fit the individual needs.

@Bean
DynamicOAuth2ConfigDetails client() {
    return new DynamicOAuth2ConfigDetails();
}
public class DynamicOAuth2ConfigDetails extends AuthorizationCodeResourceDetails {

    @Autowired
    private MyDynamicConfigService myDynamicConfigService;

    public DynamicOAuth2ConfigDetails() {
        super();
    }

    @Override
    public String getUserAuthorizationUri() {
        return myDynamicConfigService.getUserAuthorizationUri();
    }

    @Override
    public String getClientId() {
        return myDynamicConfigService.getClientId();
    }

    ...
   
}

With this simple implementation, it is possible to load the OAuth configuration at runtime in a very flexible way from different sources like databases, external services, complex configuration properties and so forth.

Categories: EngineeringSecurity

0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *