|
@@ -0,0 +1,477 @@
|
|
|
|
+[[core-model-components]]
|
|
|
|
+= Core Model / Components
|
|
|
|
+:toc: left
|
|
|
|
+:toclevels: 1
|
|
|
|
+:spring-security-reference-base-url: https://docs.spring.io/spring-security/reference
|
|
|
|
+
|
|
|
|
+[[registered-client]]
|
|
|
|
+== RegisteredClient
|
|
|
|
+
|
|
|
|
+A `RegisteredClient` is a representation of a client that is https://datatracker.ietf.org/doc/html/rfc6749#section-2[registered] with the authorization server.
|
|
|
|
+A client must be registered with the authorization server before it can initiate an authorization grant flow, such as `authorization_code` or `client_credentials`.
|
|
|
|
+
|
|
|
|
+During client registration, the client is assigned a unique https://datatracker.ietf.org/doc/html/rfc6749#section-2.2[client identifier], (optionally) a client secret (depending on https://datatracker.ietf.org/doc/html/rfc6749#section-2.1[client type]), and metadata associated with its unique client identifier.
|
|
|
|
+The client's metadata can range from human-facing display strings (such as client name) to items specific to a protocol flow (such as the list of valid redirect URIs).
|
|
|
|
+
|
|
|
|
+[TIP]
|
|
|
|
+The corresponding client registration model in Spring Security's OAuth2 Client support is {spring-security-reference-base-url}/servlet/oauth2/client/core.html#oauth2Client-client-registration[ClientRegistration].
|
|
|
|
+
|
|
|
|
+The primary purpose of a client is to request access to protected resources.
|
|
|
|
+The client first requests an access token by authenticating with the authorization server and presenting the authorization grant.
|
|
|
|
+The authorization server authenticates the client and authorization grant, and, if they are valid, issues an access token.
|
|
|
|
+The client can now request the protected resource from the resource server by presenting the access token.
|
|
|
|
+
|
|
|
|
+The following example shows how to configure a `RegisteredClient` that is allowed to perform the https://datatracker.ietf.org/doc/html/rfc6749#section-4.1[authorization_code grant] flow to request an access token:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
|
|
|
|
+ .clientId("client-a")
|
|
|
|
+ .clientSecret("{noop}secret") <1>
|
|
|
|
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
|
|
|
|
+ .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
|
|
|
+ .redirectUri("http://127.0.0.1:8080/authorized")
|
|
|
|
+ .scope("scope-a")
|
|
|
|
+ .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
|
|
|
|
+ .build();
|
|
|
|
+----
|
|
|
|
+<1> `\{noop\}` represents the `PasswordEncoder` id for Spring Security's {spring-security-reference-base-url}/features/authentication/password-storage.html#authentication-password-storage-dpe[NoOpPasswordEncoder].
|
|
|
|
+
|
|
|
|
+The corresponding configuration in Spring Security's {spring-security-reference-base-url}/servlet/oauth2/client/index.html[OAuth2 Client support] is:
|
|
|
|
+
|
|
|
|
+[source,yaml]
|
|
|
|
+----
|
|
|
|
+spring:
|
|
|
|
+ security:
|
|
|
|
+ oauth2:
|
|
|
|
+ client:
|
|
|
|
+ registration:
|
|
|
|
+ client-a:
|
|
|
|
+ provider: spring
|
|
|
|
+ client-id: client-a
|
|
|
|
+ client-secret: secret
|
|
|
|
+ authorization-grant-type: authorization_code
|
|
|
|
+ redirect-uri: "http://127.0.0.1:8080/authorized"
|
|
|
|
+ scope: scope-a
|
|
|
|
+ provider:
|
|
|
|
+ spring:
|
|
|
|
+ issuer-uri: http://localhost:9000
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+A `RegisteredClient` has metadata (attributes) associated with its unique Client Identifier and is defined as follows:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+public class RegisteredClient implements Serializable {
|
|
|
|
+ private String id; <1>
|
|
|
|
+ private String clientId; <2>
|
|
|
|
+ private Instant clientIdIssuedAt; <3>
|
|
|
|
+ private String clientSecret; <4>
|
|
|
|
+ private Instant clientSecretExpiresAt; <5>
|
|
|
|
+ private String clientName; <6>
|
|
|
|
+ private Set<ClientAuthenticationMethod> clientAuthenticationMethods; <7>
|
|
|
|
+ private Set<AuthorizationGrantType> authorizationGrantTypes; <8>
|
|
|
|
+ private Set<String> redirectUris; <9>
|
|
|
|
+ private Set<String> scopes; <10>
|
|
|
|
+ private ClientSettings clientSettings; <11>
|
|
|
|
+ private TokenSettings tokenSettings; <12>
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+<1> `id`: The ID that uniquely identifies the `RegisteredClient`.
|
|
|
|
+<2> `clientId`: The client identifier.
|
|
|
|
+<3> `clientIdIssuedAt`: The time at which the client identifier was issued.
|
|
|
|
+<4> `clientSecret`: The client's secret. The value should be encoded using Spring Security's {spring-security-reference-base-url}/features/authentication/password-storage.html#authentication-password-storage-dpe[PasswordEncoder].
|
|
|
|
+<5> `clientSecretExpiresAt`: The time at which the client secret expires.
|
|
|
|
+<6> `clientName`: A descriptive name used for the client. The name may be used in certain scenarios, such as when displaying the client name in the consent page.
|
|
|
|
+<7> `clientAuthenticationMethods`: The authentication method(s) that the client may use. The supported values are `client_secret_basic`, `client_secret_post`, https://datatracker.ietf.org/doc/html/rfc7523[`private_key_jwt`], `client_secret_jwt`, and `none` https://datatracker.ietf.org/doc/html/rfc7636[(public clients)].
|
|
|
|
+<8> `authorizationGrantTypes`: The https://datatracker.ietf.org/doc/html/rfc6749#section-1.3[authorization grant type(s)] that the client can use. The supported values are `authorization_code`, `client_credentials`, and `refresh_token`.
|
|
|
|
+<9> `redirectUris`: The registered https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2[redirect URI(s)] that the client may use in redirect-based flows – for example, `authorization_code` grant.
|
|
|
|
+<10> `scopes`: The scope(s) that the client is allowed to request.
|
|
|
|
+<11> `clientSettings`: The custom settings for the client – for example, require https://datatracker.ietf.org/doc/html/rfc7636[PKCE], require authorization consent, and others.
|
|
|
|
+<12> `tokenSettings`: The custom settings for the OAuth2 tokens issued to the client – for example, access/refresh token time-to-live, reuse refresh tokens, and others.
|
|
|
|
+
|
|
|
|
+[[registered-client-repository]]
|
|
|
|
+== RegisteredClientRepository
|
|
|
|
+
|
|
|
|
+The `RegisteredClientRepository` is the central component where new clients can be registered and existing clients can be queried.
|
|
|
|
+It is used by other components when following a specific protocol flow, such as client authentication, authorization grant processing, token introspection, dynamic client registration, and others.
|
|
|
|
+
|
|
|
|
+The provided implementations of `RegisteredClientRepository` are `InMemoryRegisteredClientRepository` and `JdbcRegisteredClientRepository`.
|
|
|
|
+The `InMemoryRegisteredClientRepository` implementation stores `RegisteredClient` instances in-memory and is recommended *ONLY* to be used during development and testing.
|
|
|
|
+`JdbcRegisteredClientRepository` is a JDBC implementation that persists `RegisteredClient` instances by using `JdbcOperations`.
|
|
|
|
+
|
|
|
|
+[NOTE]
|
|
|
|
+The `RegisteredClientRepository` is a *REQUIRED* component.
|
|
|
|
+
|
|
|
|
+The following example shows how to register a `RegisteredClientRepository` `@Bean`:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public RegisteredClientRepository registeredClientRepository() {
|
|
|
|
+ List<RegisteredClient> registrations = ...
|
|
|
|
+ return new InMemoryRegisteredClientRepository(registrations);
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Alternatively, you can configure the `RegisteredClientRepository` through the xref:configuration-model.adoc#oauth2-authorization-server-configurer[`OAuth2AuthorizationServerConfigurer`]:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
|
|
|
|
+ new OAuth2AuthorizationServerConfigurer<>();
|
|
|
|
+ http.apply(authorizationServerConfigurer);
|
|
|
|
+
|
|
|
|
+ authorizationServerConfigurer
|
|
|
|
+ .registeredClientRepository(registeredClientRepository);
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+ return http.build();
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+[[oauth2-authorization]]
|
|
|
|
+== OAuth2Authorization
|
|
|
|
+
|
|
|
|
+An `OAuth2Authorization` is a representation of an OAuth2 authorization, which holds state related to the authorization granted to a <<registered-client, client>>, by the resource owner or itself in the case of the `client_credentials` authorization grant type.
|
|
|
|
+
|
|
|
|
+[TIP]
|
|
|
|
+The corresponding authorization model in Spring Security's OAuth2 Client support is {spring-security-reference-base-url}/servlet/oauth2/client/core.html#oauth2Client-authorized-client[OAuth2AuthorizedClient].
|
|
|
|
+
|
|
|
|
+After the successful completion of an authorization grant flow, an `OAuth2Authorization` is created and associates an `OAuth2AccessToken`, an (optional) `OAuth2RefreshToken`, and additional state specific to the executed authorization grant type.
|
|
|
|
+
|
|
|
|
+The `OAuth2Token` instances associated with an `OAuth2Authorization` vary, depending on the authorization grant type.
|
|
|
|
+
|
|
|
|
+For the OAuth2 https://datatracker.ietf.org/doc/html/rfc6749#section-4.1[authorization_code grant], an `OAuth2AuthorizationCode`, an `OAuth2AccessToken`, and an (optional) `OAuth2RefreshToken` are associated.
|
|
|
|
+
|
|
|
|
+For the OpenID Connect 1.0 https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[authorization_code grant], an `OAuth2AuthorizationCode`, an `OidcIdToken`, an `OAuth2AccessToken`, and an (optional) `OAuth2RefreshToken` are associated.
|
|
|
|
+
|
|
|
|
+For the OAuth2 https://datatracker.ietf.org/doc/html/rfc6749#section-4.4[client_credentials grant], only an `OAuth2AccessToken` is associated.
|
|
|
|
+
|
|
|
|
+`OAuth2Authorization` and its attributes are defined as follows:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+public class OAuth2Authorization implements Serializable {
|
|
|
|
+ private String id; <1>
|
|
|
|
+ private String registeredClientId; <2>
|
|
|
|
+ private String principalName; <3>
|
|
|
|
+ private AuthorizationGrantType authorizationGrantType; <4>
|
|
|
|
+ private Map<Class<? extends OAuth2Token>, Token<?>> tokens; <5>
|
|
|
|
+ private Map<String, Object> attributes; <6>
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+<1> `id`: The ID that uniquely identifies the `OAuth2Authorization`.
|
|
|
|
+<2> `registeredClientId`: The ID that uniquely identifies the <<registered-client, RegisteredClient>>.
|
|
|
|
+<3> `principalName`: The principal name of the resource owner (or client).
|
|
|
|
+<4> `authorizationGrantType`: The `AuthorizationGrantType` used.
|
|
|
|
+<5> `tokens`: The `OAuth2Token` instances (and associated metadata) specific to the executed authorization grant type.
|
|
|
|
+<6> `attributes`: The additional attributes specific to the executed authorization grant type – for example, the authenticated `Principal`, `OAuth2AuthorizationRequest`, authorized scope(s), and others.
|
|
|
|
+
|
|
|
|
+`OAuth2Authorization` and its associated `OAuth2Token` instances have a set lifespan.
|
|
|
|
+A newly issued `OAuth2Token` is active and becomes inactive when it either expires or is invalidated (revoked).
|
|
|
|
+The `OAuth2Authorization` is (implicitly) inactive when all associated `OAuth2Token` instances are inactive.
|
|
|
|
+Each `OAuth2Token` is held in an `OAuth2Authorization.Token`, which provides accessors for `isExpired()`, `isInvalidated()`, and `isActive()`.
|
|
|
|
+
|
|
|
|
+`OAuth2Authorization.Token` also provides `getClaims()`, which returns the claims (if any) associated with the `OAuth2Token`.
|
|
|
|
+
|
|
|
|
+[[oauth2-authorization-service]]
|
|
|
|
+== OAuth2AuthorizationService
|
|
|
|
+
|
|
|
|
+The `OAuth2AuthorizationService` is the central component where new authorizations are stored and existing authorizations are queried.
|
|
|
|
+It is used by other components when following a specific protocol flow – for example, client authentication, authorization grant processing, token introspection, token revocation, dynamic client registration, and others.
|
|
|
|
+
|
|
|
|
+The provided implementations of `OAuth2AuthorizationService` are `InMemoryOAuth2AuthorizationService` and `JdbcOAuth2AuthorizationService`.
|
|
|
|
+The `InMemoryOAuth2AuthorizationService` implementation stores `OAuth2Authorization` instances in-memory and is recommended *ONLY* to be used during development and testing.
|
|
|
|
+`JdbcOAuth2AuthorizationService` is a JDBC implementation that persists `OAuth2Authorization` instances by using `JdbcOperations`.
|
|
|
|
+
|
|
|
|
+[NOTE]
|
|
|
|
+The `OAuth2AuthorizationService` is an *OPTIONAL* component and defaults to `InMemoryOAuth2AuthorizationService`.
|
|
|
|
+
|
|
|
|
+The following example shows how to register an `OAuth2AuthorizationService` `@Bean`:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2AuthorizationService authorizationService() {
|
|
|
|
+ return new InMemoryOAuth2AuthorizationService();
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Alternatively, you can configure the `OAuth2AuthorizationService` through the xref:configuration-model.adoc#oauth2-authorization-server-configurer[`OAuth2AuthorizationServerConfigurer`]:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
|
|
|
|
+ new OAuth2AuthorizationServerConfigurer<>();
|
|
|
|
+ http.apply(authorizationServerConfigurer);
|
|
|
|
+
|
|
|
|
+ authorizationServerConfigurer
|
|
|
|
+ .authorizationService(authorizationService);
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+ return http.build();
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+[[oauth2-authorization-consent]]
|
|
|
|
+== OAuth2AuthorizationConsent
|
|
|
|
+
|
|
|
|
+An `OAuth2AuthorizationConsent` is a representation of an authorization "consent" (decision) from an https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1[OAuth2 authorization request flow] – for example, the `authorization_code` grant, which holds the authorities granted to a <<registered-client, client>> by the resource owner.
|
|
|
|
+
|
|
|
|
+When authorizing access to a client, the resource owner may grant only a subset of the authorities requested by the client.
|
|
|
|
+The typical use case is the `authorization_code` grant flow, in which the client requests scope(s) and the resource owner grants (or denies) access to the requested scope(s).
|
|
|
|
+
|
|
|
|
+After the completion of an OAuth2 authorization request flow, an `OAuth2AuthorizationConsent` is created (or updated) and associates the granted authorities with the client and resource owner.
|
|
|
|
+
|
|
|
|
+`OAuth2AuthorizationConsent` and its attributes are defined as follows:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+public final class OAuth2AuthorizationConsent implements Serializable {
|
|
|
|
+ private final String registeredClientId; <1>
|
|
|
|
+ private final String principalName; <2>
|
|
|
|
+ private final Set<GrantedAuthority> authorities; <3>
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+<1> `registeredClientId`: The ID that uniquely identifies the <<registered-client, RegisteredClient>>.
|
|
|
|
+<2> `principalName`: The principal name of the resource owner.
|
|
|
|
+<3> `authorities`: The authorities granted to the client by the resource owner. An authority can represent a scope, a claim, a permission, a role, and others.
|
|
|
|
+
|
|
|
|
+[[oauth2-authorization-consent-service]]
|
|
|
|
+== OAuth2AuthorizationConsentService
|
|
|
|
+
|
|
|
|
+The `OAuth2AuthorizationConsentService` is the central component where new authorization consents are stored and existing authorization consents are queried.
|
|
|
|
+It is primarily used by components that implement an OAuth2 authorization request flow – for example, the `authorization_code` grant.
|
|
|
|
+
|
|
|
|
+The provided implementations of `OAuth2AuthorizationConsentService` are `InMemoryOAuth2AuthorizationConsentService` and `JdbcOAuth2AuthorizationConsentService`.
|
|
|
|
+The `InMemoryOAuth2AuthorizationConsentService` implementation stores `OAuth2AuthorizationConsent` instances in-memory and is recommended *ONLY* for development and testing.
|
|
|
|
+`JdbcOAuth2AuthorizationConsentService` is a JDBC implementation that persists `OAuth2AuthorizationConsent` instances by using `JdbcOperations`.
|
|
|
|
+
|
|
|
|
+[NOTE]
|
|
|
|
+The `OAuth2AuthorizationConsentService` is an *OPTIONAL* component and defaults to `InMemoryOAuth2AuthorizationConsentService`.
|
|
|
|
+
|
|
|
|
+The following example shows how to register an `OAuth2AuthorizationConsentService` `@Bean`:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2AuthorizationConsentService authorizationConsentService() {
|
|
|
|
+ return new InMemoryOAuth2AuthorizationConsentService();
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Alternatively, you can configure the `OAuth2AuthorizationConsentService` through the xref:configuration-model.adoc#oauth2-authorization-server-configurer[`OAuth2AuthorizationServerConfigurer`]:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
|
|
|
|
+ new OAuth2AuthorizationServerConfigurer<>();
|
|
|
|
+ http.apply(authorizationServerConfigurer);
|
|
|
|
+
|
|
|
|
+ authorizationServerConfigurer
|
|
|
|
+ .authorizationConsentService(authorizationConsentService);
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+ return http.build();
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+[[oauth2-token-context]]
|
|
|
|
+== OAuth2TokenContext
|
|
|
|
+
|
|
|
|
+An `OAuth2TokenContext` is a context object that holds information associated with an `OAuth2Token` and is used by an <<oauth2-token-generator, OAuth2TokenGenerator>> and <<oauth2-token-customizer, OAuth2TokenCustomizer>>.
|
|
|
|
+
|
|
|
|
+`OAuth2TokenContext` provides the following accessors:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+public interface OAuth2TokenContext extends Context {
|
|
|
|
+
|
|
|
|
+ default RegisteredClient getRegisteredClient() ... <1>
|
|
|
|
+
|
|
|
|
+ default <T extends Authentication> T getPrincipal() ... <2>
|
|
|
|
+
|
|
|
|
+ default ProviderContext getProviderContext() ... <3>
|
|
|
|
+
|
|
|
|
+ @Nullable
|
|
|
|
+ default OAuth2Authorization getAuthorization() ... <4>
|
|
|
|
+
|
|
|
|
+ default Set<String> getAuthorizedScopes() ... <5>
|
|
|
|
+
|
|
|
|
+ default OAuth2TokenType getTokenType() ... <6>
|
|
|
|
+
|
|
|
|
+ default AuthorizationGrantType getAuthorizationGrantType() ... <7>
|
|
|
|
+
|
|
|
|
+ default <T extends Authentication> T getAuthorizationGrant() ... <8>
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+<1> `getRegisteredClient()`: The <<registered-client, RegisteredClient>> associated with the authorization grant.
|
|
|
|
+<2> `getPrincipal()`: The `Authentication` instance of the resource owner (or client).
|
|
|
|
+<3> `getProviderContext()`: The xref:configuration-model.adoc#provider-context[`ProviderContext`] object that holds information related to the provider.
|
|
|
|
+<4> `getAuthorization()`: The <<oauth2-authorization, OAuth2Authorization>> associated with the authorization grant.
|
|
|
|
+<5> `getAuthorizedScopes()`: The scope(s) authorized for the client.
|
|
|
|
+<6> `getTokenType()`: The `OAuth2TokenType` to generate. The supported values are `code`, `access_token`, `refresh_token`, and `id_token`.
|
|
|
|
+<7> `getAuthorizationGrantType()`: The `AuthorizationGrantType`.
|
|
|
|
+<8> `getAuthorizationGrant()`: The `Authentication` instance used by the `AuthenticationProvider` that processes the authorization grant.
|
|
|
|
+
|
|
|
|
+[[oauth2-token-generator]]
|
|
|
|
+== OAuth2TokenGenerator
|
|
|
|
+
|
|
|
|
+An `OAuth2TokenGenerator` is responsible for generating an `OAuth2Token` from the information contained in the provided <<oauth2-token-context, OAuth2TokenContext>>.
|
|
|
|
+
|
|
|
|
+The `OAuth2Token` generated primarily depends on the type of `OAuth2TokenType` specified in the `OAuth2TokenContext`.
|
|
|
|
+
|
|
|
|
+For example, when the `value` for `OAuth2TokenType` is:
|
|
|
|
+
|
|
|
|
+* `code`, then `OAuth2AuthorizationCode` is generated.
|
|
|
|
+* `access_token`, then `OAuth2AccessToken` is generated.
|
|
|
|
+* `refresh_token`, then `OAuth2RefreshToken` is generated.
|
|
|
|
+* `id_token`, then `OidcIdToken` is generated.
|
|
|
|
+
|
|
|
|
+Furthermore, the format of the generated `OAuth2AccessToken` varies, depending on the `TokenSettings.getAccessTokenFormat()` configured for the <<registered-client, RegisteredClient>>.
|
|
|
|
+If the format is `OAuth2TokenFormat.SELF_CONTAINED` (the default), then a `Jwt` is generated.
|
|
|
|
+If the format is `OAuth2TokenFormat.REFERENCE`, then an "opaque" token is generated.
|
|
|
|
+
|
|
|
|
+Finally, if the generated `OAuth2Token` has a set of claims and implements `ClaimAccessor`, the claims are made accessible from <<oauth2-authorization, OAuth2Authorization.Token.getClaims()>>.
|
|
|
|
+
|
|
|
|
+The `OAuth2TokenGenerator` is primarily used by components that implement authorization grant processing – for example, `authorization_code`, `client_credentials`, and `refresh_token`.
|
|
|
|
+
|
|
|
|
+The provided implementations are `OAuth2AccessTokenGenerator`, `OAuth2RefreshTokenGenerator`, and `JwtGenerator`.
|
|
|
|
+The `OAuth2AccessTokenGenerator` generates an "opaque" (`OAuth2TokenFormat.REFERENCE`) access token, and the `JwtGenerator` generates a `Jwt` (`OAuth2TokenFormat.SELF_CONTAINED`).
|
|
|
|
+
|
|
|
|
+[NOTE]
|
|
|
|
+The `OAuth2TokenGenerator` is an *OPTIONAL* component and defaults to a `DelegatingOAuth2TokenGenerator` composed of an `OAuth2AccessTokenGenerator` and `OAuth2RefreshTokenGenerator`.
|
|
|
|
+As well, if a `JwtEncoder` `@Bean` or `JWKSource<SecurityContext>` `@Bean` is registered, then a `JwtGenerator` is additionally composed in the `DelegatingOAuth2TokenGenerator`.
|
|
|
|
+
|
|
|
|
+The `OAuth2TokenGenerator` provides great flexibility, as it can support any custom token format for `access_token` and `refresh_token`.
|
|
|
|
+
|
|
|
|
+The following example shows how to register an `OAuth2TokenGenerator` `@Bean`:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2TokenGenerator<?> tokenGenerator() {
|
|
|
|
+ JwtEncoder jwtEncoder = ...
|
|
|
|
+ JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
|
|
|
|
+ OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
|
|
|
|
+ OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
|
|
|
+ return new DelegatingOAuth2TokenGenerator(
|
|
|
|
+ jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+Alternatively, you can configure the `OAuth2TokenGenerator` through the xref:configuration-model.adoc#oauth2-authorization-server-configurer[`OAuth2AuthorizationServerConfigurer`]:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
|
|
|
|
+ OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer =
|
|
|
|
+ new OAuth2AuthorizationServerConfigurer<>();
|
|
|
|
+ http.apply(authorizationServerConfigurer);
|
|
|
|
+
|
|
|
|
+ authorizationServerConfigurer
|
|
|
|
+ .tokenGenerator(tokenGenerator);
|
|
|
|
+
|
|
|
|
+ ...
|
|
|
|
+
|
|
|
|
+ return http.build();
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+[[oauth2-token-customizer]]
|
|
|
|
+== OAuth2TokenCustomizer
|
|
|
|
+
|
|
|
|
+An `OAuth2TokenCustomizer` provides the ability to customize the attributes of an `OAuth2Token`, which are accessible in the provided <<oauth2-token-context, OAuth2TokenContext>>.
|
|
|
|
+It is used by an <<oauth2-token-generator, OAuth2TokenGenerator>> to let it customize the attributes of the `OAuth2Token` before it is generated.
|
|
|
|
+
|
|
|
|
+An `OAuth2TokenCustomizer<OAuth2TokenClaimsContext>` declared with a generic type of `OAuth2TokenClaimsContext` (`implements OAuth2TokenContext`) provides the ability to customize the claims of an "opaque" `OAuth2AccessToken`.
|
|
|
|
+`OAuth2TokenClaimsContext.getClaims()` provides access to the `OAuth2TokenClaimsSet.Builder`, allowing the ability to add, replace, and remove claims.
|
|
|
|
+
|
|
|
|
+The following example shows how to implement an `OAuth2TokenCustomizer<OAuth2TokenClaimsContext>` and configure it with an `OAuth2AccessTokenGenerator`:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2TokenGenerator<?> tokenGenerator() {
|
|
|
|
+ JwtEncoder jwtEncoder = ...
|
|
|
|
+ JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
|
|
|
|
+ OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
|
|
|
|
+ accessTokenGenerator.setAccessTokenCustomizer(accessTokenCustomizer());
|
|
|
|
+ OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
|
|
|
+ return new DelegatingOAuth2TokenGenerator(
|
|
|
|
+ jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2TokenCustomizer<OAuth2TokenClaimsContext> accessTokenCustomizer() {
|
|
|
|
+ return context -> {
|
|
|
|
+ OAuth2TokenClaimsSet.Builder claims = context.getClaims();
|
|
|
|
+ // Customize claims
|
|
|
|
+
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+[TIP]
|
|
|
|
+If the `OAuth2TokenGenerator` is not provided as a `@Bean` or is not configured through the `OAuth2AuthorizationServerConfigurer`, an `OAuth2TokenCustomizer<OAuth2TokenClaimsContext>` `@Bean` will automatically be configured with an `OAuth2AccessTokenGenerator`.
|
|
|
|
+
|
|
|
|
+An `OAuth2TokenCustomizer<JwtEncodingContext>` declared with a generic type of `JwtEncodingContext` (`implements OAuth2TokenContext`) provides the ability to customize the headers and claims of a `Jwt`.
|
|
|
|
+`JwtEncodingContext.getHeaders()` provides access to the `JoseHeader.Builder`, allowing the ability to add, replace, and remove headers.
|
|
|
|
+`JwtEncodingContext.getClaims()` provides access to the `JwtClaimsSet.Builder`, allowing the ability to add, replace, and remove claims.
|
|
|
|
+
|
|
|
|
+The following example shows how to implement an `OAuth2TokenCustomizer<JwtEncodingContext>` and configure it with a `JwtGenerator`:
|
|
|
|
+
|
|
|
|
+[source,java]
|
|
|
|
+----
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2TokenGenerator<?> tokenGenerator() {
|
|
|
|
+ JwtEncoder jwtEncoder = ...
|
|
|
|
+ JwtGenerator jwtGenerator = new JwtGenerator(jwtEncoder);
|
|
|
|
+ jwtGenerator.setJwtCustomizer(jwtCustomizer());
|
|
|
|
+ OAuth2AccessTokenGenerator accessTokenGenerator = new OAuth2AccessTokenGenerator();
|
|
|
|
+ OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator();
|
|
|
|
+ return new DelegatingOAuth2TokenGenerator(
|
|
|
|
+ jwtGenerator, accessTokenGenerator, refreshTokenGenerator);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+@Bean
|
|
|
|
+public OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
|
|
|
|
+ return context -> {
|
|
|
|
+ JoseHeader.Builder headers = context.getHeaders();
|
|
|
|
+ JwtClaimsSet.Builder claims = context.getClaims();
|
|
|
|
+ if (context.getTokenType().equals(OAuth2TokenType.ACCESS_TOKEN)) {
|
|
|
|
+ // Customize headers/claims for access_token
|
|
|
|
+
|
|
|
|
+ } else if (context.getTokenType().getValue().equals(OidcParameterNames.ID_TOKEN)) {
|
|
|
|
+ // Customize headers/claims for id_token
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+----
|
|
|
|
+
|
|
|
|
+[TIP]
|
|
|
|
+If the `OAuth2TokenGenerator` is not provided as a `@Bean` or is not configured through the `OAuth2AuthorizationServerConfigurer`, an `OAuth2TokenCustomizer<JwtEncodingContext>` `@Bean` will automatically be configured with a `JwtGenerator`.
|