parent
f425c96f06
commit
f874a12ddb
|
@ -529,8 +529,8 @@ client-registration.attlist &=
|
||||||
## The method used to authenticate the client with the provider. The supported values are client_secret_basic, client_secret_post and none (public clients).
|
## The method used to authenticate the client with the provider. The supported values are client_secret_basic, client_secret_post and none (public clients).
|
||||||
attribute client-authentication-method {"client_secret_basic" | "basic" | "client_secret_post" | "post" | "none"}?
|
attribute client-authentication-method {"client_secret_basic" | "basic" | "client_secret_post" | "post" | "none"}?
|
||||||
client-registration.attlist &=
|
client-registration.attlist &=
|
||||||
## The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The supported values are authorization_code, client_credentials, password and implicit.
|
## The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The supported values are authorization_code, client_credentials, password, implicit, as well as, extension grant type urn:ietf:params:oauth:grant-type:jwt-bearer.
|
||||||
attribute authorization-grant-type {"authorization_code" | "client_credentials" | "password" | "implicit"}?
|
attribute authorization-grant-type {"authorization_code" | "client_credentials" | "password" | "implicit" | "urn:ietf:params:oauth:grant-type:jwt-bearer"}?
|
||||||
client-registration.attlist &=
|
client-registration.attlist &=
|
||||||
## The client’s registered redirect URI that the Authorization Server redirects the end-user’s user-agent to after the end-user has authenticated and authorized access to the client.
|
## The client’s registered redirect URI that the Authorization Server redirects the end-user’s user-agent to after the end-user has authenticated and authorized access to the client.
|
||||||
attribute redirect-uri {xsd:token}?
|
attribute redirect-uri {xsd:token}?
|
||||||
|
|
|
@ -1673,7 +1673,8 @@
|
||||||
<xs:attribute name="authorization-grant-type">
|
<xs:attribute name="authorization-grant-type">
|
||||||
<xs:annotation>
|
<xs:annotation>
|
||||||
<xs:documentation>The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The
|
<xs:documentation>The OAuth 2.0 Authorization Framework defines four Authorization Grant types. The
|
||||||
supported values are authorization_code, client_credentials, password and implicit.
|
supported values are authorization_code, client_credentials, password, implicit, as well
|
||||||
|
as, extension grant type urn:ietf:params:oauth:grant-type:jwt-bearer.
|
||||||
</xs:documentation>
|
</xs:documentation>
|
||||||
</xs:annotation>
|
</xs:annotation>
|
||||||
<xs:simpleType>
|
<xs:simpleType>
|
||||||
|
@ -1682,6 +1683,7 @@
|
||||||
<xs:enumeration value="client_credentials"/>
|
<xs:enumeration value="client_credentials"/>
|
||||||
<xs:enumeration value="password"/>
|
<xs:enumeration value="password"/>
|
||||||
<xs:enumeration value="implicit"/>
|
<xs:enumeration value="implicit"/>
|
||||||
|
<xs:enumeration value="urn:ietf:params:oauth:grant-type:jwt-bearer"/>
|
||||||
</xs:restriction>
|
</xs:restriction>
|
||||||
</xs:simpleType>
|
</xs:simpleType>
|
||||||
</xs:attribute>
|
</xs:attribute>
|
||||||
|
|
|
@ -1067,7 +1067,7 @@ The supported values are *client_secret_basic*, *client_secret_post* and *none*
|
||||||
[[nsa-client-registration-authorization-grant-type]]
|
[[nsa-client-registration-authorization-grant-type]]
|
||||||
* **authorization-grant-type**
|
* **authorization-grant-type**
|
||||||
The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types.
|
The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types.
|
||||||
The supported values are `authorization_code`, `client_credentials` and `password`.
|
The supported values are `authorization_code`, `client_credentials`, `password`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`.
|
||||||
|
|
||||||
|
|
||||||
[[nsa-client-registration-redirect-uri]]
|
[[nsa-client-registration-redirect-uri]]
|
||||||
|
|
|
@ -10,6 +10,7 @@ At a high-level, the core features available are:
|
||||||
* https://tools.ietf.org/html/rfc6749#section-6[Refresh Token]
|
* https://tools.ietf.org/html/rfc6749#section-6[Refresh Token]
|
||||||
* https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials]
|
* https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials]
|
||||||
* https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials]
|
* https://tools.ietf.org/html/rfc6749#section-1.3.3[Resource Owner Password Credentials]
|
||||||
|
* https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[JWT Bearer]
|
||||||
|
|
||||||
.HTTP Client support
|
.HTTP Client support
|
||||||
* <<oauth2Client-webclient-servlet, `WebClient` integration for Servlet Environments>> (for requesting protected resources)
|
* <<oauth2Client-webclient-servlet, `WebClient` integration for Servlet Environments>> (for requesting protected resources)
|
||||||
|
@ -153,6 +154,7 @@ The following sections will go into more detail on the core components used by O
|
||||||
** <<oauth2Client-refresh-token-grant, Refresh Token>>
|
** <<oauth2Client-refresh-token-grant, Refresh Token>>
|
||||||
** <<oauth2Client-client-creds-grant, Client Credentials>>
|
** <<oauth2Client-client-creds-grant, Client Credentials>>
|
||||||
** <<oauth2Client-password-grant, Resource Owner Password Credentials>>
|
** <<oauth2Client-password-grant, Resource Owner Password Credentials>>
|
||||||
|
** <<oauth2Client-jwt-bearer-grant, JWT Bearer>>
|
||||||
* <<oauth2Client-additional-features>>
|
* <<oauth2Client-additional-features>>
|
||||||
** <<oauth2Client-registered-authorized-client, Resolving an Authorized Client>>
|
** <<oauth2Client-registered-authorized-client, Resolving an Authorized Client>>
|
||||||
* <<oauth2Client-webclient-servlet>>
|
* <<oauth2Client-webclient-servlet>>
|
||||||
|
@ -207,7 +209,7 @@ public final class ClientRegistration {
|
||||||
<4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider.
|
<4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider.
|
||||||
The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)].
|
The supported values are *client_secret_basic*, *client_secret_post* and *none* https://tools.ietf.org/html/rfc6749#section-2.1[(public clients)].
|
||||||
<5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types.
|
<5> `authorizationGrantType`: The OAuth 2.0 Authorization Framework defines four https://tools.ietf.org/html/rfc6749#section-1.3[Authorization Grant] types.
|
||||||
The supported values are `authorization_code`, `client_credentials` and `password`.
|
The supported values are `authorization_code`, `client_credentials`, `password`, as well as, extension grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`.
|
||||||
<6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent
|
<6> `redirectUri`: The client's registered redirect URI that the _Authorization Server_ redirects the end-user's user-agent
|
||||||
to after the end-user has authenticated and authorized access to the client.
|
to after the end-user has authenticated and authorized access to the client.
|
||||||
<7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile.
|
<7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile.
|
||||||
|
@ -1631,6 +1633,224 @@ class OAuth2ClientController {
|
||||||
If not provided, it will default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`.
|
If not provided, it will default to `ServletRequestAttributes` using `RequestContextHolder.getRequestAttributes()`.
|
||||||
|
|
||||||
|
|
||||||
|
[[oauth2Client-jwt-bearer-grant]]
|
||||||
|
==== JWT Bearer
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Please refer to JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants for further details on the https://datatracker.ietf.org/doc/html/rfc7523[JWT Bearer] grant.
|
||||||
|
|
||||||
|
|
||||||
|
===== Requesting an Access Token
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
Please refer to the https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[Access Token Request/Response] protocol flow for the JWT Bearer grant.
|
||||||
|
|
||||||
|
The default implementation of `OAuth2AccessTokenResponseClient` for the JWT Bearer grant is `DefaultJwtBearerTokenResponseClient`, which uses a `RestOperations` when requesting an access token at the Authorization Server’s Token Endpoint.
|
||||||
|
|
||||||
|
The `DefaultJwtBearerTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response.
|
||||||
|
|
||||||
|
|
||||||
|
===== Customizing the Access Token Request
|
||||||
|
|
||||||
|
If you need to customize the pre-processing of the Token Request, you can provide `DefaultJwtBearerTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<JwtBearerGrantRequest, RequestEntity<?>>`.
|
||||||
|
The default implementation `JwtBearerGrantRequestEntityConverter` builds a `RequestEntity` representation of a https://datatracker.ietf.org/doc/html/rfc7523#section-2.1[OAuth 2.0 Access Token Request].
|
||||||
|
However, providing a custom `Converter`, would allow you to extend the Token Request and add custom parameter(s).
|
||||||
|
|
||||||
|
|
||||||
|
===== Customizing the Access Token Response
|
||||||
|
|
||||||
|
On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultJwtBearerTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
|
||||||
|
The default `RestOperations` is configured as follows:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
|
||||||
|
new FormHttpMessageConverter(),
|
||||||
|
new OAuth2AccessTokenResponseHttpMessageConverter()));
|
||||||
|
|
||||||
|
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
val restTemplate = RestTemplate(listOf(
|
||||||
|
FormHttpMessageConverter(),
|
||||||
|
OAuth2AccessTokenResponseHttpMessageConverter()))
|
||||||
|
|
||||||
|
restTemplate.errorHandler = OAuth2ErrorResponseErrorHandler()
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
TIP: Spring MVC `FormHttpMessageConverter` is required as it's used when sending the OAuth 2.0 Access Token Request.
|
||||||
|
|
||||||
|
`OAuth2AccessTokenResponseHttpMessageConverter` is a `HttpMessageConverter` for an OAuth 2.0 Access Token Response.
|
||||||
|
You can provide `OAuth2AccessTokenResponseHttpMessageConverter.setTokenResponseConverter()` with a custom `Converter<Map<String, String>, OAuth2AccessTokenResponse>` that is used for converting the OAuth 2.0 Access Token Response parameters to an `OAuth2AccessTokenResponse`.
|
||||||
|
|
||||||
|
`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error, eg. 400 Bad Request.
|
||||||
|
It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
|
||||||
|
|
||||||
|
Whether you customize `DefaultJwtBearerTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
// Customize
|
||||||
|
OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> jwtBearerTokenResponseClient = ...
|
||||||
|
|
||||||
|
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider = new JwtBearerOAuth2AuthorizedClientProvider();
|
||||||
|
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient);
|
||||||
|
|
||||||
|
OAuth2AuthorizedClientProvider authorizedClientProvider =
|
||||||
|
OAuth2AuthorizedClientProviderBuilder.builder()
|
||||||
|
.provider(jwtBearerAuthorizedClientProvider)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
// Customize
|
||||||
|
val jwtBearerTokenResponseClient: OAuth2AccessTokenResponseClient<JwtBearerGrantRequest> = ...
|
||||||
|
|
||||||
|
val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
|
||||||
|
jwtBearerAuthorizedClientProvider.setAccessTokenResponseClient(jwtBearerTokenResponseClient);
|
||||||
|
|
||||||
|
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||||
|
.provider(jwtBearerAuthorizedClientProvider)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
===== Using the Access Token
|
||||||
|
|
||||||
|
Given the following Spring Boot 2.x properties for an OAuth 2.0 Client registration:
|
||||||
|
|
||||||
|
[source,yaml]
|
||||||
|
----
|
||||||
|
spring:
|
||||||
|
security:
|
||||||
|
oauth2:
|
||||||
|
client:
|
||||||
|
registration:
|
||||||
|
okta:
|
||||||
|
client-id: okta-client-id
|
||||||
|
client-secret: okta-client-secret
|
||||||
|
authorization-grant-type: urn:ietf:params:oauth:grant-type:jwt-bearer
|
||||||
|
scope: read
|
||||||
|
provider:
|
||||||
|
okta:
|
||||||
|
token-uri: https://dev-1234.oktapreview.com/oauth2/v1/token
|
||||||
|
----
|
||||||
|
|
||||||
|
...and the `OAuth2AuthorizedClientManager` `@Bean`:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
public OAuth2AuthorizedClientManager authorizedClientManager(
|
||||||
|
ClientRegistrationRepository clientRegistrationRepository,
|
||||||
|
OAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||||
|
|
||||||
|
JwtBearerOAuth2AuthorizedClientProvider jwtBearerAuthorizedClientProvider =
|
||||||
|
new JwtBearerOAuth2AuthorizedClientProvider();
|
||||||
|
|
||||||
|
OAuth2AuthorizedClientProvider authorizedClientProvider =
|
||||||
|
OAuth2AuthorizedClientProviderBuilder.builder()
|
||||||
|
.provider(jwtBearerAuthorizedClientProvider)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
|
||||||
|
new DefaultOAuth2AuthorizedClientManager(
|
||||||
|
clientRegistrationRepository, authorizedClientRepository);
|
||||||
|
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
|
||||||
|
|
||||||
|
return authorizedClientManager;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
fun authorizedClientManager(
|
||||||
|
clientRegistrationRepository: ClientRegistrationRepository,
|
||||||
|
authorizedClientRepository: OAuth2AuthorizedClientRepository): OAuth2AuthorizedClientManager {
|
||||||
|
val jwtBearerAuthorizedClientProvider = JwtBearerOAuth2AuthorizedClientProvider()
|
||||||
|
val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
|
||||||
|
.provider(jwtBearerAuthorizedClientProvider)
|
||||||
|
.build()
|
||||||
|
val authorizedClientManager = DefaultOAuth2AuthorizedClientManager(
|
||||||
|
clientRegistrationRepository, authorizedClientRepository)
|
||||||
|
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
|
||||||
|
return authorizedClientManager
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
You may obtain the `OAuth2AccessToken` as follows:
|
||||||
|
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@RestController
|
||||||
|
public class OAuth2ResourceServerController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OAuth2AuthorizedClientManager authorizedClientManager;
|
||||||
|
|
||||||
|
@GetMapping("/resource")
|
||||||
|
public String resource(JwtAuthenticationToken jwtAuthentication) {
|
||||||
|
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
|
||||||
|
.principal(jwtAuthentication)
|
||||||
|
.build();
|
||||||
|
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
|
||||||
|
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
class OAuth2ResourceServerController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var authorizedClientManager: OAuth2AuthorizedClientManager
|
||||||
|
|
||||||
|
@GetMapping("/resource")
|
||||||
|
fun resource(jwtAuthentication: JwtAuthenticationToken?): String {
|
||||||
|
val authorizeRequest: OAuth2AuthorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
|
||||||
|
.principal(jwtAuthentication)
|
||||||
|
.build()
|
||||||
|
val authorizedClient = authorizedClientManager.authorize(authorizeRequest)
|
||||||
|
val accessToken: OAuth2AccessToken = authorizedClient.accessToken
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
|
||||||
[[oauth2Client-additional-features]]
|
[[oauth2Client-additional-features]]
|
||||||
=== Additional Features
|
=== Additional Features
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue