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.
0 Comments