Document new features for OAuth Client

Fixes gh-5832
This commit is contained in:
Joe Grandja 2018-10-10 16:56:09 -04:00
parent a26eadc600
commit 26fcde6f8e
4 changed files with 895 additions and 671 deletions

View File

@ -1,13 +1,10 @@
[[oauth2login-advanced]]
== OAuth 2.0 Login -- Advanced Configuration
`HttpSecurity.oauth2Login()` provides a number of configuration options for customizing OAuth 2.0 Login.
The main configuration options are grouped into their protocol endpoint counterparts.
For example, `oauth2Login().authorizationEndpoint()` allows configuring the _Authorization Endpoint_,
whereas `oauth2Login().tokenEndpoint()` allows configuring the _Token Endpoint_.
For example, `oauth2Login().authorizationEndpoint()` allows configuring the _Authorization Endpoint_, whereas `oauth2Login().tokenEndpoint()` allows configuring the _Token Endpoint_.
The following code shows an example:
@ -43,14 +40,12 @@ The authorization process utilizes two authorization server endpoints (HTTP reso
As well as one client endpoint:
* Redirection Endpoint: Used by the authorization server to return responses
containing authorization credentials to the client via the resource owner user-agent.
* Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent.
The OpenID Connect Core 1.0 specification defines the http://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] as follows:
The UserInfo Endpoint is an OAuth 2.0 Protected Resource that returns claims about the authenticated end-user.
To obtain the requested claims about the end-user, the client makes a request to the UserInfo Endpoint
by using an access token obtained through OpenID Connect Authentication.
To obtain the requested claims about the end-user, the client makes a request to the UserInfo Endpoint by using an access token obtained through OpenID Connect Authentication.
These claims are normally represented by a JSON object that contains a collection of name-value pairs for the claims.
The following code shows the complete configuration options available for the `oauth2Login()` DSL:
@ -65,11 +60,13 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
http
.oauth2Login()
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientRepository(this.authorizedClientRepository())
.authorizedClientService(this.authorizedClientService())
.loginPage("/login")
.authorizationEndpoint()
.baseUri(this.authorizationRequestBaseUri())
.authorizationRequestRepository(this.authorizationRequestRepository())
.authorizationRequestResolver(this.authorizationRequestResolver())
.and()
.redirectionEndpoint()
.baseUri(this.authorizationResponseBaseUri())
@ -86,12 +83,10 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
----
The sections to follow go into more detail on each of the configuration options available:
The following sections go into more detail on each of the configuration options available:
* <<oauth2login-advanced-login-page>>
* <<oauth2login-advanced-authorization-endpoint>>
* <<oauth2login-advanced-redirection-endpoint>>
* <<oauth2login-advanced-token-endpoint>>
* <<oauth2login-advanced-userinfo-endpoint>>
@ -99,8 +94,7 @@ The sections to follow go into more detail on each of the configuration options
=== OAuth 2.0 Login Page
By default, the OAuth 2.0 Login Page is auto-generated by the `DefaultLoginPageGeneratingFilter`.
The default login page shows each configured OAuth Client with its `ClientRegistration.clientName`
as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login).
The default login page shows each configured OAuth Client with its `ClientRegistration.clientName` as a link, which is capable of initiating the Authorization Request (or OAuth 2.0 Login).
The link's destination for each OAuth Client defaults to the following:
@ -113,8 +107,7 @@ The following line shows an example:
<a href="/oauth2/authorization/google">Google</a>
----
To override the default login page,
configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`.
To override the default login page, configure `oauth2Login().loginPage()` and (optionally) `oauth2Login().authorizationEndpoint().baseUri()`.
The following listing shows an example:
@ -152,52 +145,11 @@ The following line shows an example:
----
====
[[oauth2login-advanced-authorization-endpoint]]
=== Authorization Endpoint
[[oauth2login-advanced-authorization-request-repository]]
==== `AuthorizationRequestRepository`
`AuthorizationRequestRepository` is responsible for the persistence of the `OAuth2AuthorizationRequest`
from the time the Authorization Request is initiated to the time the Authorization Response
is received (the callback).
[TIP]
The `OAuth2AuthorizationRequest` is used to correlate and validate the Authorization Response.
The default implementation of `AuthorizationRequestRepository` is `HttpSessionOAuth2AuthorizationRequestRepository`,
which stores the `OAuth2AuthorizationRequest` in the `HttpSession`.
If you would like to provide a custom implementation of `AuthorizationRequestRepository`
that stores the attributes of `OAuth2AuthorizationRequest` in a `Cookie`,
configure it as shown in the following example:
[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
...
}
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
return new HttpCookieOAuth2AuthorizationRequestRepository();
}
}
----
[[oauth2login-advanced-redirection-endpoint]]
=== Redirection Endpoint
The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response
(which contains the authorization credentials) to the client via the Resource Owner user-agent.
The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response (which contains the authorization credentials) to the client via the Resource Owner user-agent.
[TIP]
OAuth 2.0 Login leverages the Authorization Code Grant.
@ -239,74 +191,34 @@ return CommonOAuth2Provider.GOOGLE.getBuilder("google")
----
====
[[oauth2login-advanced-token-endpoint]]
=== Token Endpoint
[[oauth2login-advanced-token-client]]
==== OAuth2AccessTokenResponseClient
`OAuth2AccessTokenResponseClient` is responsible for exchanging an authorization grant credential
for an access token credential at the Authorization Server's Token Endpoint.
The default implementation of `OAuth2AccessTokenResponseClient` is `NimbusAuthorizationCodeTokenResponseClient`,
which exchanges an authorization code for an access token at the Token Endpoint.
[NOTE]
`NimbusAuthorizationCodeTokenResponseClient` uses the https://connect2id.com/products/nimbus-oauth-openid-connect-sdk[Nimbus OAuth 2.0 SDK] internally.
If you would like to provide a custom implementation of `OAuth2AccessTokenResponseClient`
that uses Spring Framework 5 reactive `WebClient` for initiating requests to the Token Endpoint,
configure it as shown in the following example:
[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Login()
.tokenEndpoint()
.accessTokenResponseClient(this.accessTokenResponseClient())
...
}
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
return new SpringWebClientAuthorizationCodeTokenResponseClient();
}
}
----
[[oauth2login-advanced-userinfo-endpoint]]
=== UserInfo Endpoint
The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections:
* <<oauth2login-advanced-map-authorities>>
* <<oauth2login-advanced-custom-user>>
* <<oauth2login-advanced-oauth2-user-service>>
* <<oauth2login-advanced-oidc-user-service>>
* <<oauth2login-advanced-map-authorities, Mapping User Authorities>>
* <<oauth2login-advanced-custom-user, Configuring a Custom OAuth2User>>
* <<oauth2login-advanced-oauth2-user-service, OAuth 2.0 UserService>>
* <<oauth2login-advanced-oidc-user-service, OpenID Connect 1.0 UserService>>
[[oauth2login-advanced-map-authorities]]
==== Mapping User Authorities
After the user successfully authenticates with the OAuth 2.0 Provider,
the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances,
which will be supplied to `OAuth2AuthenticationToken` when completing the authentication.
After the user successfully authenticates with the OAuth 2.0 Provider, the `OAuth2User.getAuthorities()` (or `OidcUser.getAuthorities()`) may be mapped to a new set of `GrantedAuthority` instances, which will be supplied to `OAuth2AuthenticationToken` when completing the authentication.
[TIP]
`OAuth2AuthenticationToken.getAuthorities()` is used for authorizing requests, such as in `hasRole('USER')` or `hasRole('ADMIN')`.
There are a couple of options to choose from when mapping user authorities:
* <<oauth2login-advanced-map-authorities-grantedauthoritiesmapper,Using a `GrantedAuthoritiesMapper`>>
* <<oauth2login-advanced-map-authorities-oauth2userservice,Delegation-based strategy with `OAuth2UserService`>>
* <<oauth2login-advanced-map-authorities-grantedauthoritiesmapper, Using a GrantedAuthoritiesMapper>>
* <<oauth2login-advanced-map-authorities-oauth2userservice, Delegation-based strategy with OAuth2UserService>>
[[oauth2login-advanced-map-authorities-grantedauthoritiesmapper]]
===== Using a `GrantedAuthoritiesMapper`
===== Using a GrantedAuthoritiesMapper
Provide an implementation of `GrantedAuthoritiesMapper` and configure it as shown in the following example:
@ -374,16 +286,13 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
----
[[oauth2login-advanced-map-authorities-oauth2userservice]]
===== Delegation-based strategy with `OAuth2UserService`
===== Delegation-based strategy with OAuth2UserService
This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible
as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService)
or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService).
This strategy is advanced compared to using a `GrantedAuthoritiesMapper`, however, it's also more flexible as it gives you access to the `OAuth2UserRequest` and `OAuth2User` (when using an OAuth 2.0 UserService) or `OidcUserRequest` and `OidcUser` (when using an OpenID Connect 1.0 UserService).
The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`,
which is very useful in the cases where the _delegator_ needs to fetch authority information
from a protected resource before it can map the custom authorities for the user.
The `OAuth2UserRequest` (and `OidcUserRequest`) provides you access to the associated `OAuth2AccessToken`, which is very useful in the cases where the _delegator_ needs to fetch authority information from a protected resource before it can map the custom authorities for the user.
The following example shows how to implement and configure a delegation-based strategy using an OpenID Connect 1.0 UserService:
@ -424,14 +333,13 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
----
[[oauth2login-advanced-custom-user]]
==== Configuring a Custom OAuth2User
`CustomUserTypesOAuth2UserService` is an implementation of an `OAuth2UserService`
that provides support for custom `OAuth2User` types.
`CustomUserTypesOAuth2UserService` is an implementation of an `OAuth2UserService` that provides support for custom `OAuth2User` types.
If the default implementation (`DefaultOAuth2User`) does not suit your needs,
you can define your own implementation of `OAuth2User`.
If the default implementation (`DefaultOAuth2User`) does not suit your needs, you can define your own implementation of `OAuth2User`.
The following code demonstrates how you would register a custom `OAuth2User` type for GitHub:
@ -521,22 +429,33 @@ public class GitHubOAuth2User implements OAuth2User {
For detailed information returned from the UserInfo Endpoint, see the API documentation
for https://developer.github.com/v3/users/#get-the-authenticated-user["Get the authenticated user"].
[[oauth2login-advanced-oauth2-user-service]]
==== OAuth 2.0 UserService
`DefaultOAuth2UserService` is an implementation of an `OAuth2UserService`
that supports standard OAuth 2.0 Provider's.
`DefaultOAuth2UserService` is an implementation of an `OAuth2UserService` that supports standard OAuth 2.0 Provider's.
[NOTE]
`OAuth2UserService` obtains the user attributes
of the end-user (the resource owner) from the UserInfo Endpoint (by using the
access token granted to the client during the authorization flow)
and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`.
`OAuth2UserService` obtains the user attributes of the end-user (the resource owner) from the UserInfo Endpoint (by using the access token granted to the client during the authorization flow) and returns an `AuthenticatedPrincipal` in the form of an `OAuth2User`.
If the default implementation does not suit your needs, you can define your own implementation of `OAuth2UserService`
for standard OAuth 2.0 Provider's.
`DefaultOAuth2UserService` uses a `RestOperations` when requesting the user attributes at the UserInfo Endpoint.
The following configuration demonstrates how to configure a custom `OAuth2UserService`:
If you need to customize the pre-processing of the UserInfo Request, you can provide `DefaultOAuth2UserService.setRequestEntityConverter()` with a custom `Converter<OAuth2UserRequest, RequestEntity<?>>`.
The default implementation `OAuth2UserRequestEntityConverter` builds a `RequestEntity` representation of a UserInfo Request that sets the `OAuth2AccessToken` in the `Authorization` header by default.
On the other end, if you need to customize the post-handling of the UserInfo Response, you will need to provide `DefaultOAuth2UserService.setRestOperations()` with a custom configured `RestOperations`.
The default `RestOperations` is configured as follows:
[source,java]
----
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
----
`OAuth2ErrorResponseErrorHandler` is a `ResponseErrorHandler` that can handle an OAuth 2.0 Error (400 Bad Request).
It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
Whether you customize `DefaultOAuth2UserService` or provide your own implementation of `OAuth2UserService`, you'll need to configure it as shown in the following example:
[source,java]
----
@ -553,27 +472,22 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() {
return new CustomOAuth2UserService();
...
}
}
----
[[oauth2login-advanced-oidc-user-service]]
==== OpenID Connect 1.0 UserService
`OidcUserService` is an implementation of an `OAuth2UserService`
that supports OpenID Connect 1.0 Provider's.
`OidcUserService` is an implementation of an `OAuth2UserService` that supports OpenID Connect 1.0 Provider's.
[NOTE]
`OAuth2UserService` is responsible for obtaining the user attributes
of the end user (the resource owner) from the UserInfo Endpoint (by using the
access token granted to the client during the authorization flow)
and return an `AuthenticatedPrincipal` in the form of an `OidcUser`.
The `OidcUserService` leverages the `DefaultOAuth2UserService` when requesting the user attributes at the UserInfo Endpoint.
If the default implementation does not suit your needs, you can define your own implementation of `OAuth2UserService`
for OpenID Connect 1.0 Provider's.
If you need to customize the pre-processing of the UserInfo Request and/or the post-handling of the UserInfo Response, you will need to provide `OidcUserService.setOauth2UserService()` with a custom configured `DefaultOAuth2UserService`.
The following configuration demonstrates how to configure a custom OpenID Connect 1.0 `OAuth2UserService`:
Whether you customize `OidcUserService` or provide your own implementation of `OAuth2UserService` for OpenID Connect 1.0 Provider's, you'll need to configure it as shown in the following example:
[source,java]
----
@ -590,7 +504,7 @@ public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
return new CustomOidcUserService();
...
}
}
----

View File

@ -384,541 +384,10 @@ If not configured a status code 200 will be returned by default.
- Documentation for the <<nsa-logout, logout element>> in the Spring Security XML Namespace section
[[jc-oauth2login]]
== OAuth 2.0 Login
include::oauth2-client.adoc[]
The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g.
GitHub) or OpenID Connect 1.0 Provider (such as Google).
OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub".
include::oauth2-login.adoc[]
NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0].
[[jc-oauth2login-sample-boot]]
=== Spring Boot 2.0 Sample
Spring Boot 2.0 brings full auto-configuration capabilities for OAuth 2.0 Login.
This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] using _Google_ as the _Authentication Provider_ and covers the following topics:
* <<jc-oauth2login-sample-initial-setup,Initial setup>>
* <<jc-oauth2login-sample-redirect-uri,Setting the redirect URI>>
* <<jc-oauth2login-sample-application-config,Configure `application.yml`>>
* <<jc-oauth2login-sample-boot-application,Boot up the application>>
[[jc-oauth2login-sample-initial-setup]]
==== Initial setup
To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials.
NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the http://openid.net/connect/[OpenID Connect 1.0] specification and is http://openid.net/certification/[OpenID Certified].
Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0".
After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret.
[[jc-oauth2login-sample-redirect-uri]]
==== Setting the redirect URI
The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<<jc-oauth2login-sample-initial-setup,created in the previous step>>)_ on the Consent page.
In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`.
TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`.
The *_registrationId_* is a unique identifier for the <<jc-oauth2login-client-registration,ClientRegistration>>.
[[jc-oauth2login-sample-application-config]]
==== Configure `application.yml`
Now that you have a new OAuth Client with Google, you need to configure the application to use the OAuth Client for the _authentication flow_.
To do so:
. Go to `application.yml` and set the following configuration:
+
[source,yaml]
----
spring:
security:
oauth2:
client:
registration: <1>
google: <2>
client-id: google-client-id
client-secret: google-client-secret
----
+
.OAuth Client properties
====
<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties.
<2> Following the base property prefix is the ID for the <<jc-oauth2login-client-registration,ClientRegistration>>, such as google.
====
. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier.
[[jc-oauth2login-sample-boot-application]]
==== Boot up the application
Launch the Spring Boot 2.0 sample and go to `http://localhost:8080`.
You are then redirected to the default _auto-generated_ login page, which displays a link for Google.
Click on the Google link, and you are then redirected to Google for authentication.
After authenticating with your Google account credentials, the next page presented to you is the Consent screen.
The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier.
Click *Allow* to authorize the OAuth Client to access your email address and basic profile information.
At this point, the OAuth Client retrieves your email address and basic profile information from the http://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] and establishes an authenticated session.
[[jc-oauth2login-client-registration]]
=== ClientRegistration
`ClientRegistration` is a representation of a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider.
A client registration holds information, such as client id, client secret,
authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details.
`ClientRegistration` and its properties are defined as follows:
[source,java]
----
public final class ClientRegistration {
private String registrationId; <1>
private String clientId; <2>
private String clientSecret; <3>
private ClientAuthenticationMethod clientAuthenticationMethod; <4>
private AuthorizationGrantType authorizationGrantType; <5>
private String redirectUriTemplate; <6>
private Set<String> scopes; <7>
private ProviderDetails providerDetails;
private String clientName; <8>
public class ProviderDetails {
private String authorizationUri; <9>
private String tokenUri; <10>
private UserInfoEndpoint userInfoEndpoint;
private String jwkSetUri; <11>
public class UserInfoEndpoint {
private String uri; <12>
private String userNameAttributeName; <13>
}
}
}
----
<1> `registrationId`: The ID that uniquely identifies the `ClientRegistration`.
<2> `clientId`: The client identifier.
<3> `clientSecret`: The client secret.
<4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider.
The supported values are *basic* and *post*.
<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 and implicit.
<6> `redirectUriTemplate`: 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 default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`, which supports URI template variables.
<7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile.
<8> `clientName`: A descriptive name used for the client.
The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page.
<9> `authorizationUri`: The Authorization Endpoint URI for the Authorization Server.
<10> `tokenUri`: The Token Endpoint URI for the Authorization Server.
<11> `jwkSetUri`: The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server,
which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response.
<12> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user.
<13> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user.
[[jc-oauth2login-boot-property-mappings]]
=== Spring Boot 2.0 Property Mappings
The following table outlines the mapping of the Spring Boot 2.0 OAuth Client properties to the `ClientRegistration` properties.
|===
|Spring Boot 2.0 |ClientRegistration
|`spring.security.oauth2.client.registration._[registrationId]_`
|`registrationId`
|`spring.security.oauth2.client.registration._[registrationId]_.client-id`
|`clientId`
|`spring.security.oauth2.client.registration._[registrationId]_.client-secret`
|`clientSecret`
|`spring.security.oauth2.client.registration._[registrationId]_.client-authentication-method`
|`clientAuthenticationMethod`
|`spring.security.oauth2.client.registration._[registrationId]_.authorization-grant-type`
|`authorizationGrantType`
|`spring.security.oauth2.client.registration._[registrationId]_.redirect-uri-template`
|`redirectUriTemplate`
|`spring.security.oauth2.client.registration._[registrationId]_.scope`
|`scopes`
|`spring.security.oauth2.client.registration._[registrationId]_.client-name`
|`clientName`
|`spring.security.oauth2.client.provider._[providerId]_.authorization-uri`
|`providerDetails.authorizationUri`
|`spring.security.oauth2.client.provider._[providerId]_.token-uri`
|`providerDetails.tokenUri`
|`spring.security.oauth2.client.provider._[providerId]_.jwk-set-uri`
|`providerDetails.jwkSetUri`
|`spring.security.oauth2.client.provider._[providerId]_.user-info-uri`
|`providerDetails.userInfoEndpoint.uri`
|`spring.security.oauth2.client.provider._[providerId]_.userNameAttribute`
|`providerDetails.userInfoEndpoint.userNameAttributeName`
|===
[[jc-oauth2login-client-registration-repo]]
=== ClientRegistrationRepository
The `ClientRegistrationRepository` serves as a repository for OAuth 2.0 / OpenID Connect 1.0 `ClientRegistration`(s).
[NOTE]
Client registration information is ultimately stored and owned by the associated Authorization Server.
This repository provides the ability to retrieve a sub-set of the primary client registration information,
which is stored with the Authorization Server.
Spring Boot 2.0 auto-configuration binds each of the properties under `spring.security.oauth2.client.registration._[registrationId]_`
to an instance of `ClientRegistration` and then composes each of the `ClientRegistration` instance(s) within a `ClientRegistrationRepository`.
[NOTE]
The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`.
The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext`
so that it is available for dependency-injection, if needed by the application.
The following listing shows an example:
[source,java]
----
@Controller
public class OAuth2LoginController {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@RequestMapping("/")
public String index() {
ClientRegistration googleRegistration =
this.clientRegistrationRepository.findByRegistrationId("google");
...
return "index";
}
}
----
[[jc-oauth2login-common-oauth2-provider]]
=== CommonOAuth2Provider
`CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta.
For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a Provider.
Therefore, it makes sense to provide default values in order to reduce the required configuration.
As demonstrated previously, when we <<jc-oauth2login-sample-application-config,configured a Google client>>, only the `client-id` and `client-secret` properties are required.
The following listing shows an example:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
google:
client-id: google-client-id
client-secret: google-client-secret
----
[TIP]
The auto-defaulting of client properties works seamlessly here because the `registrationId` (`google`) matches the `GOOGLE` `enum` (case-insensitive) in `CommonOAuth2Provider`.
For cases where you may want to specify a different `registrationId`, such as `google-login`,
you can still leverage auto-defaulting of client properties by configuring the `provider` property.
The following listing shows an example:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
google-login: <1>
provider: google <2>
client-id: google-client-id
client-secret: google-client-secret
----
<1> The `registrationId` is set to `google-login`.
<2> The `provider` property is set to `google`, which will leverage the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`.
[[jc-oauth2login-custom-provider-properties]]
=== Configuring Custom Provider Properties
There are some OAuth 2.0 Providers that support multi-tenancy, which results in different protocol endpoints for each tenant (or sub-domain).
For example, an OAuth Client registered with Okta is assigned to a specific sub-domain and have their own protocol endpoints.
For these cases, Spring Boot 2.0 provides the following base property for configuring custom provider properties: `spring.security.oauth2.client.provider._[providerId]_`.
The following listing shows an example:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
provider:
okta: <1>
authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
user-name-attribute: sub
jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys
----
<1> The base property (`spring.security.oauth2.client.provider.okta`) allows for custom configuration of protocol endpoint locations.
[[jc-oauth2login-override-boot-autoconfig]]
=== Overriding Spring Boot 2.0 Auto-configuration
The Spring Boot 2.0 Auto-configuration class for OAuth Client support is `OAuth2ClientAutoConfiguration`.
It performs the following tasks:
* Registers a `ClientRegistrationRepository` `@Bean` composed of `ClientRegistration`(s) from the configured OAuth Client properties.
* Provides a `WebSecurityConfigurerAdapter` `@Configuration` and enables OAuth 2.0 Login through `httpSecurity.oauth2Login()`.
If you need to override the auto-configuration based on your specific requirements, you may do so in the following ways:
* <<jc-oauth2login-register-clientregistrationrepository-bean,Register a `ClientRegistrationRepository` `@Bean`>>
* <<jc-oauth2login-provide-websecurityconfigureradapter,Provide a `WebSecurityConfigurerAdapter`>>
* <<jc-oauth2login-completely-override-autoconfiguration,Completely Override the Auto-configuration>>
[[jc-oauth2login-register-clientregistrationrepository-bean]]
==== Register a `ClientRegistrationRepository` `@Bean`
The following example shows how to register a `ClientRegistrationRepository` `@Bean`:
[source,java]
----
@Configuration
public class OAuth2LoginConfig {
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("openid", "profile", "email", "address", "phone")
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build();
}
}
----
[[jc-oauth2login-provide-websecurityconfigureradapter]]
==== Provide a `WebSecurityConfigurerAdapter`
The following example shows how to provide a `WebSecurityConfigurerAdapter` with `@EnableWebSecurity` and enable OAuth 2.0 login through `httpSecurity.oauth2Login()`:
[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
----
[[jc-oauth2login-completely-override-autoconfiguration]]
==== Completely Override the Auto-configuration
The following example shows how to completely override the auto-configuration by both registering a `ClientRegistrationRepository` `@Bean` and providing a `WebSecurityConfigurerAdapter`, both of which were described in the two preceding sections.
[source,java]
----
@Configuration
public class OAuth2LoginConfig {
@EnableWebSecurity
public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("openid", "profile", "email", "address", "phone")
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build();
}
}
----
[[jc-oauth2login-javaconfig-wo-boot]]
=== Java Configuration without Spring Boot 2.0
If you are not able to use Spring Boot 2.0 and would like to configure one of the pre-defined providers in `CommonOAuth2Provider` (for example, Google), apply the following configuration:
[source,java]
----
@Configuration
public class OAuth2LoginConfig {
@EnableWebSecurity
public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
@Bean
public OAuth2AuthorizedClientService authorizedClientService() {
return new InMemoryOAuth2AuthorizedClientService(this.clientRegistrationRepository());
}
private ClientRegistration googleClientRegistration() {
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.build();
}
}
----
[[jc-oauth2login-authorized-client]]
=== OAuth2AuthorizedClient / OAuth2AuthorizedClientService
`OAuth2AuthorizedClient` is a representation of an Authorized Client.
A client is considered to be authorized when the end-user (Resource Owner) has granted authorization to the client to access its protected resources.
`OAuth2AuthorizedClient` serves the purpose of associating an `OAuth2AccessToken` to a `ClientRegistration` (client) and resource owner, who is the `Principal` end-user that granted the authorization.
The primary role of the `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient` instances.
From a developer perspective, it provides the capability to lookup an `OAuth2AccessToken` associated with a client so that it may be used to initiate a request to a resource server.
[NOTE]
Spring Boot 2.0 Auto-configuration registers an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`.
The developer may also register an `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext` (overriding Spring Boot 2.0 Auto-configuration) in order to have the ability to lookup an `OAuth2AccessToken` associated with a specific `ClientRegistration` (client).
The following listing shows an example:
[source,java]
----
@Controller
public class OAuth2LoginController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@RequestMapping("/userinfo")
public String userinfo(OAuth2AuthenticationToken authentication) {
// authentication.getAuthorizedClientRegistrationId() returns the
// registrationId of the Client that was authorized during the Login flow
OAuth2AuthorizedClient authorizedClient =
this.authorizedClientService.loadAuthorizedClient(
authentication.getAuthorizedClientRegistrationId(),
authentication.getName());
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "userinfo";
}
}
----
[[jc-oauth2login-resources]]
=== Additional Resources
The following additional resources describe advanced configuration options:
* <<oauth2login-advanced-login-page, OAuth 2.0 Login Page>>
* Authorization Endpoint:
** <<oauth2login-advanced-authorization-request-repository, AuthorizationRequestRepository>>
* <<oauth2login-advanced-redirection-endpoint, Redirection Endpoint>>
* Token Endpoint:
** <<oauth2login-advanced-token-client, OAuth2AccessTokenResponseClient>>
* UserInfo Endpoint:
** <<oauth2login-advanced-map-authorities, Mapping User Authorities>>
** <<oauth2login-advanced-custom-user, Configuring a Custom OAuth2User>>
** <<oauth2login-advanced-oauth2-user-service, OAuth 2.0 UserService>>
** <<oauth2login-advanced-oidc-user-service, OpenID Connect 1.0 UserService>>
[[oauth2resourceserver]]
== OAuth 2.0 Resource Server

View File

@ -0,0 +1,435 @@
[[oauth2client]]
== OAuth 2.0 Client
The OAuth 2.0 Client features provide support for the Client role as defined in the https://tools.ietf.org/html/rfc6749#section-1.1[OAuth 2.0 Authorization Framework].
The following main features are available:
* https://tools.ietf.org/html/rfc6749#section-1.3.1[Authorization Code Grant]
* https://tools.ietf.org/html/rfc6749#section-1.3.4[Client Credentials Grant]
* <<servlet-webclient, `WebClient` extension for Servlet Environments>> (for making protected resource requests)
`HttpSecurity.oauth2Client()` provides a number of configuration options for customizing OAuth 2.0 Client.
The following code shows the complete configuration options available for the `oauth2Client()` DSL:
[source,java]
----
@EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Client()
.clientRegistrationRepository(this.clientRegistrationRepository())
.authorizedClientRepository(this.authorizedClientRepository())
.authorizedClientService(this.authorizedClientService())
.authorizationCodeGrant()
.authorizationRequestRepository(this.authorizationRequestRepository())
.authorizationRequestResolver(this.authorizationRequestResolver())
.accessTokenResponseClient(this.accessTokenResponseClient());
}
}
----
The following sections go into more detail on each of the configuration options available:
* <<oauth2Client-client-registration>>
* <<oauth2Client-client-registration-repo>>
* <<oauth2Client-authorized-client>>
* <<oauth2Client-authorized-repo-service>>
* <<oauth2Client-registered-authorized-client>>
* <<oauth2Client-authorization-request-repository>>
* <<oauth2Client-authorization-request-resolver>>
* <<oauth2Client-access-token-client>>
[[oauth2Client-client-registration]]
=== ClientRegistration
`ClientRegistration` is a representation of a client registered with an OAuth 2.0 or OpenID Connect 1.0 Provider.
A client registration holds information, such as client id, client secret, authorization grant type, redirect URI, scope(s), authorization URI, token URI, and other details.
`ClientRegistration` and its properties are defined as follows:
[source,java]
----
public final class ClientRegistration {
private String registrationId; <1>
private String clientId; <2>
private String clientSecret; <3>
private ClientAuthenticationMethod clientAuthenticationMethod; <4>
private AuthorizationGrantType authorizationGrantType; <5>
private String redirectUriTemplate; <6>
private Set<String> scopes; <7>
private ProviderDetails providerDetails;
private String clientName; <8>
public class ProviderDetails {
private String authorizationUri; <9>
private String tokenUri; <10>
private UserInfoEndpoint userInfoEndpoint;
private String jwkSetUri; <11>
private Map<String, Object> configurationMetadata; <12>
public class UserInfoEndpoint {
private String uri; <13>
private AuthenticationMethod authenticationMethod; <14>
private String userNameAttributeName; <15>
}
}
}
----
<1> `registrationId`: The ID that uniquely identifies the `ClientRegistration`.
<2> `clientId`: The client identifier.
<3> `clientSecret`: The client secret.
<4> `clientAuthenticationMethod`: The method used to authenticate the Client with the Provider.
The supported values are *basic* and *post*.
<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, implicit, and client_credentials.
<6> `redirectUriTemplate`: 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.
<7> `scopes`: The scope(s) requested by the client during the Authorization Request flow, such as openid, email, or profile.
<8> `clientName`: A descriptive name used for the client.
The name may be used in certain scenarios, such as when displaying the name of the client in the auto-generated login page.
<9> `authorizationUri`: The Authorization Endpoint URI for the Authorization Server.
<10> `tokenUri`: The Token Endpoint URI for the Authorization Server.
<11> `jwkSetUri`: The URI used to retrieve the https://tools.ietf.org/html/rfc7517[JSON Web Key (JWK)] Set from the Authorization Server,
which contains the cryptographic key(s) used to verify the https://tools.ietf.org/html/rfc7515[JSON Web Signature (JWS)] of the ID Token and optionally the UserInfo Response.
<12> `configurationMetadata`: The https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig[OpenID Provider Configuration Information].
This information will only be available if the Spring Boot 2.x property `spring.security.oauth2.client.provider.[providerId].issuerUri` is configured.
<13> `(userInfoEndpoint)uri`: The UserInfo Endpoint URI used to access the claims/attributes of the authenticated end-user.
<14> `(userInfoEndpoint)authenticationMethod`: The authentication method used when sending the access token to the UserInfo Endpoint.
The supported values are *header*, *form* and *query*.
<15> `userNameAttributeName`: The name of the attribute returned in the UserInfo Response that references the Name or Identifier of the end-user.
[[oauth2Client-client-registration-repo]]
=== ClientRegistrationRepository
The `ClientRegistrationRepository` serves as a repository for OAuth 2.0 / OpenID Connect 1.0 `ClientRegistration`(s).
[NOTE]
Client registration information is ultimately stored and owned by the associated Authorization Server.
This repository provides the ability to retrieve a sub-set of the primary client registration information, which is stored with the Authorization Server.
Spring Boot 2.x auto-configuration binds each of the properties under `spring.security.oauth2.client.registration._[registrationId]_` to an instance of `ClientRegistration` and then composes each of the `ClientRegistration` instance(s) within a `ClientRegistrationRepository`.
[NOTE]
The default implementation of `ClientRegistrationRepository` is `InMemoryClientRegistrationRepository`.
The auto-configuration also registers the `ClientRegistrationRepository` as a `@Bean` in the `ApplicationContext` so that it is available for dependency-injection, if needed by the application.
The following listing shows an example:
[source,java]
----
@Controller
public class OAuth2ClientController {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@RequestMapping("/")
public String index() {
ClientRegistration googleRegistration =
this.clientRegistrationRepository.findByRegistrationId("google");
...
return "index";
}
}
----
[[oauth2Client-authorized-client]]
=== OAuth2AuthorizedClient
`OAuth2AuthorizedClient` is a representation of an Authorized Client.
A client is considered to be authorized when the end-user (Resource Owner) has granted authorization to the client to access its protected resources.
`OAuth2AuthorizedClient` serves the purpose of associating an `OAuth2AccessToken` (and optional `OAuth2RefreshToken`) to a `ClientRegistration` (client) and resource owner, who is the `Principal` end-user that granted the authorization.
[[oauth2Client-authorized-repo-service]]
=== OAuth2AuthorizedClientRepository / OAuth2AuthorizedClientService
`OAuth2AuthorizedClientRepository` is responsible for persisting `OAuth2AuthorizedClient`(s) between web requests.
Whereas, the primary role of `OAuth2AuthorizedClientService` is to manage `OAuth2AuthorizedClient`(s) at the application-level.
From a developer perspective, the `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` provides the capability to lookup an `OAuth2AccessToken` associated with a client so that it may be used to initiate a protected resource request.
[NOTE]
Spring Boot 2.x auto-configuration registers an `OAuth2AuthorizedClientRepository` and/or `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext`.
The developer may also register an `OAuth2AuthorizedClientRepository` or `OAuth2AuthorizedClientService` `@Bean` in the `ApplicationContext` (overriding Spring Boot 2.x auto-configuration) in order to have the ability to lookup an `OAuth2AccessToken` associated with a specific `ClientRegistration` (client).
The following listing shows an example:
[source,java]
----
@Controller
public class OAuth2LoginController {
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@RequestMapping("/userinfo")
public String userinfo(OAuth2AuthenticationToken authentication) {
// authentication.getAuthorizedClientRegistrationId() returns the
// registrationId of the Client that was authorized during the oauth2Login() flow
OAuth2AuthorizedClient authorizedClient =
this.authorizedClientService.loadAuthorizedClient(
authentication.getAuthorizedClientRegistrationId(),
authentication.getName());
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "userinfo";
}
}
----
[[oauth2Client-registered-authorized-client]]
=== RegisteredOAuth2AuthorizedClient
The `@RegisteredOAuth2AuthorizedClient` annotation provides the capability of resolving a method parameter to an argument value of type `OAuth2AuthorizedClient`.
This is a convenient alternative compared to looking up the `OAuth2AuthorizedClient` via the `OAuth2AuthorizedClientService`.
[source,java]
----
@Controller
public class OAuth2LoginController {
@RequestMapping("/userinfo")
public String userinfo(@RegisteredOAuth2AuthorizedClient("google") OAuth2AuthorizedClient authorizedClient) {
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
...
return "userinfo";
}
}
----
The `@RegisteredOAuth2AuthorizedClient` annotation is handled by `OAuth2AuthorizedClientArgumentResolver` and provides the following capabilities:
* An `OAuth2AccessToken` will automatically be requested if the client has not yet been authorized.
** For `authorization_code`, this involves triggering the authorization request redirect to initiate the flow
** For `client_credentials`, the access token is directly obtained from the Token Endpoint using `DefaultClientCredentialsTokenResponseClient`
[[oauth2Client-authorization-request-repository]]
=== AuthorizationRequestRepository
`AuthorizationRequestRepository` is responsible for the persistence of the `OAuth2AuthorizationRequest` from the time the Authorization Request is initiated to the time the Authorization Response is received (the callback).
[TIP]
The `OAuth2AuthorizationRequest` is used to correlate and validate the Authorization Response.
The default implementation of `AuthorizationRequestRepository` is `HttpSessionOAuth2AuthorizationRequestRepository`, which stores the `OAuth2AuthorizationRequest` in the `HttpSession`.
If you would like to provide a custom implementation of `AuthorizationRequestRepository` that stores the attributes of `OAuth2AuthorizationRequest` in a `Cookie`, you may configure it as shown in the following example:
[source,java]
----
@EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Client()
.authorizationCodeGrant()
.authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
...
}
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
return new HttpCookieOAuth2AuthorizationRequestRepository();
}
}
----
[[oauth2Client-authorization-request-resolver]]
=== OAuth2AuthorizationRequestResolver
The primary role of the `OAuth2AuthorizationRequestResolver` is to resolve an `OAuth2AuthorizationRequest` from the provided web request.
The default implementation `DefaultOAuth2AuthorizationRequestResolver` matches on the (default) path `/oauth2/authorization/{registrationId}` extracting the `registrationId` and using it to build the `OAuth2AuthorizationRequest` for the associated `ClientRegistration`.
One of the primary use cases an `OAuth2AuthorizationRequestResolver` can realize is the ability to customize the Authorization Request with additional parameters above the standard parameters defined in the OAuth 2.0 Authorization Framework.
For example, OpenID Connect defines additional OAuth 2.0 request parameters for the https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[Authorization Code Flow] extending from the standard parameters defined in the https://tools.ietf.org/html/rfc6749#section-4.1.1[OAuth 2.0 Authorization Framework].
One of those extended parameters is the `prompt` parameter.
[NOTE]
OPTIONAL. Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent. The defined values are: none, login, consent, select_account
The following example shows how to implement an `OAuth2AuthorizationRequestResolver` that customizes the Authorization Request for `oauth2Login()`, by including the request parameter `prompt=consent`.
[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestResolver(
new CustomAuthorizationRequestResolver(
this.clientRegistrationRepository)); <1>
}
}
public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
private final OAuth2AuthorizationRequestResolver defaultAuthorizationRequestResolver;
public CustomAuthorizationRequestResolver(
ClientRegistrationRepository clientRegistrationRepository) {
this.defaultAuthorizationRequestResolver =
new DefaultOAuth2AuthorizationRequestResolver(
clientRegistrationRepository, "/oauth2/authorization");
}
@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
OAuth2AuthorizationRequest authorizationRequest =
this.defaultAuthorizationRequestResolver.resolve(request); <2>
return authorizationRequest != null ? <3>
customAuthorizationRequest(authorizationRequest) :
null;
}
@Override
public OAuth2AuthorizationRequest resolve(
HttpServletRequest request, String clientRegistrationId) {
OAuth2AuthorizationRequest authorizationRequest =
this.defaultAuthorizationRequestResolver.resolve(
request, clientRegistrationId); <2>
return authorizationRequest != null ? <3>
customAuthorizationRequest(authorizationRequest) :
null;
}
private OAuth2AuthorizationRequest customAuthorizationRequest(
OAuth2AuthorizationRequest authorizationRequest) {
Map<String, Object> additionalParameters =
new LinkedHashMap<>(authorizationRequest.getAdditionalParameters());
additionalParameters.put("prompt", "consent"); <4>
return OAuth2AuthorizationRequest.from(authorizationRequest) <5>
.additionalParameters(additionalParameters) <6>
.build();
}
}
----
<1> Configure the custom `OAuth2AuthorizationRequestResolver`
<2> Attempt to resolve the `OAuth2AuthorizationRequest` using the `DefaultOAuth2AuthorizationRequestResolver`
<3> If an `OAuth2AuthorizationRequest` was resolved than return a customized version else return `null`
<4> Add custom parameters to the existing `OAuth2AuthorizationRequest.additionalParameters`
<5> Create a copy of the default `OAuth2AuthorizationRequest` which returns an `OAuth2AuthorizationRequest.Builder` for further modifications
<6> Override the default `additionalParameters`
[TIP]
`OAuth2AuthorizationRequest.Builder.build()` constructs the `OAuth2AuthorizationRequest.authorizationRequestUri`, which represents the complete Authorization Request URI including all query parameters using the `application/x-www-form-urlencoded` format.
The preceding example shows the common use case of adding a custom parameter on top of the standard parameters.
However, if you need to remove or change a standard parameter or your requirements are more advanced, than you can take full control in building the Authorization Request URI by simply overriding the `OAuth2AuthorizationRequest.authorizationRequestUri` property.
The following example shows a variation of the `customAuthorizationRequest()` method from the preceding example, and instead overrides the `OAuth2AuthorizationRequest.authorizationRequestUri` property.
[source,java]
----
private OAuth2AuthorizationRequest customAuthorizationRequest(
OAuth2AuthorizationRequest authorizationRequest) {
String customAuthorizationRequestUri = UriComponentsBuilder
.fromUriString(authorizationRequest.getAuthorizationRequestUri())
.queryParam("prompt", "consent")
.build(true)
.toUriString();
return OAuth2AuthorizationRequest.from(authorizationRequest)
.authorizationRequestUri(customAuthorizationRequestUri)
.build();
}
----
[[oauth2Client-access-token-client]]
=== OAuth2AccessTokenResponseClient
The primary role of the `OAuth2AccessTokenResponseClient` is to exchange an authorization grant credential for an access token credential at the Authorization Server's Token Endpoint.
The default implementation of `OAuth2AccessTokenResponseClient` for the `authorization_code` grant is `DefaultAuthorizationCodeTokenResponseClient`, which uses a `RestOperations` for exchanging an authorization code for an access token at the Token Endpoint.
The `DefaultAuthorizationCodeTokenResponseClient` is quite flexible as it allows you to customize the pre-processing of the Token Request and/or post-handling of the Token Response.
If you need to customize the pre-processing of the Token Request, you can provide `DefaultAuthorizationCodeTokenResponseClient.setRequestEntityConverter()` with a custom `Converter<OAuth2AuthorizationCodeGrantRequest, RequestEntity<?>>`.
The default implementation `OAuth2AuthorizationCodeGrantRequestEntityConverter` builds a `RequestEntity` representation of a standard https://tools.ietf.org/html/rfc6749#section-4.1.3[OAuth 2.0 Access Token Request].
However, providing a custom `Converter`, would allow you to extend the standard Token Request and add a custom parameter for example.
IMPORTANT: The custom `Converter` must return a valid `RequestEntity` representation of an OAuth 2.0 Access Token Request that is understood by the intended OAuth 2.0 Provider.
On the other end, if you need to customize the post-handling of the Token Response, you will need to provide `DefaultAuthorizationCodeTokenResponseClient.setRestOperations()` with a custom configured `RestOperations`.
The default `RestOperations` is configured as follows:
[source,java]
----
RestTemplate restTemplate = new RestTemplate(Arrays.asList(
new FormHttpMessageConverter(),
new OAuth2AccessTokenResponseHttpMessageConverter()));
restTemplate.setErrorHandler(new 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 (400 Bad Request).
It uses an `OAuth2ErrorHttpMessageConverter` for converting the OAuth 2.0 Error parameters to an `OAuth2Error`.
Whether you customize `DefaultAuthorizationCodeTokenResponseClient` or provide your own implementation of `OAuth2AccessTokenResponseClient`, you'll need to configure it as shown in the following example:
[source,java]
----
@EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.oauth2Client()
.authorizationCodeGrant()
.accessTokenResponseClient(this.customAccessTokenResponseClient())
...
}
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> customAccessTokenResponseClient() {
...
}
}
----

View File

@ -0,0 +1,406 @@
[[oauth2login]]
== OAuth 2.0 Login
The OAuth 2.0 Login feature provides an application with the capability to have users log in to the application by using their existing account at an OAuth 2.0 Provider (e.g. GitHub) or OpenID Connect 1.0 Provider (such as Google).
OAuth 2.0 Login implements the use cases: "Login with Google" or "Login with GitHub".
NOTE: OAuth 2.0 Login is implemented by using the *Authorization Code Grant*, as specified in the https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0 Authorization Framework] and http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[OpenID Connect Core 1.0].
[[oauth2login-sample-boot]]
=== Spring Boot 2.x Sample
Spring Boot 2.x brings full auto-configuration capabilities for OAuth 2.0 Login.
This section shows how to configure the {gh-samples-url}/boot/oauth2login[*OAuth 2.0 Login sample*] using _Google_ as the _Authentication Provider_ and covers the following topics:
* <<oauth2login-sample-initial-setup,Initial setup>>
* <<oauth2login-sample-redirect-uri,Setting the redirect URI>>
* <<oauth2login-sample-application-config,Configure application.yml>>
* <<oauth2login-sample-boot-application,Boot up the application>>
[[oauth2login-sample-initial-setup]]
==== Initial setup
To use Google's OAuth 2.0 authentication system for login, you must set up a project in the Google API Console to obtain OAuth 2.0 credentials.
NOTE: https://developers.google.com/identity/protocols/OpenIDConnect[Google's OAuth 2.0 implementation] for authentication conforms to the http://openid.net/connect/[OpenID Connect 1.0] specification and is http://openid.net/certification/[OpenID Certified].
Follow the instructions on the https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect] page, starting in the section, "Setting up OAuth 2.0".
After completing the "Obtain OAuth 2.0 credentials" instructions, you should have a new OAuth Client with credentials consisting of a Client ID and a Client Secret.
[[oauth2login-sample-redirect-uri]]
==== Setting the redirect URI
The redirect URI is the path in the application that the end-user's user-agent is redirected back to after they have authenticated with Google and have granted access to the OAuth Client _(<<oauth2login-sample-initial-setup,created in the previous step>>)_ on the Consent page.
In the "Set a redirect URI" sub-section, ensure that the *Authorized redirect URIs* field is set to `http://localhost:8080/login/oauth2/code/google`.
TIP: The default redirect URI template is `{baseUrl}/login/oauth2/code/{registrationId}`.
The *_registrationId_* is a unique identifier for the <<oauth2Client-client-registration,ClientRegistration>>.
[[oauth2login-sample-application-config]]
==== Configure application.yml
Now that you have a new OAuth Client with Google, you need to configure the application to use the OAuth Client for the _authentication flow_.
To do so:
. Go to `application.yml` and set the following configuration:
+
[source,yaml]
----
spring:
security:
oauth2:
client:
registration: <1>
google: <2>
client-id: google-client-id
client-secret: google-client-secret
----
+
.OAuth Client properties
====
<1> `spring.security.oauth2.client.registration` is the base property prefix for OAuth Client properties.
<2> Following the base property prefix is the ID for the <<oauth2Client-client-registration,ClientRegistration>>, such as google.
====
. Replace the values in the `client-id` and `client-secret` property with the OAuth 2.0 credentials you created earlier.
[[oauth2login-sample-boot-application]]
==== Boot up the application
Launch the Spring Boot 2.x sample and go to `http://localhost:8080`.
You are then redirected to the default _auto-generated_ login page, which displays a link for Google.
Click on the Google link, and you are then redirected to Google for authentication.
After authenticating with your Google account credentials, the next page presented to you is the Consent screen.
The Consent screen asks you to either allow or deny access to the OAuth Client you created earlier.
Click *Allow* to authorize the OAuth Client to access your email address and basic profile information.
At this point, the OAuth Client retrieves your email address and basic profile information from the http://openid.net/specs/openid-connect-core-1_0.html#UserInfo[UserInfo Endpoint] and establishes an authenticated session.
[[oauth2login-boot-property-mappings]]
=== Spring Boot 2.x Property Mappings
The following table outlines the mapping of the Spring Boot 2.x OAuth Client properties to the <<oauth2Client-client-registration,ClientRegistration>> properties.
|===
|Spring Boot 2.x |ClientRegistration
|`spring.security.oauth2.client.registration._[registrationId]_`
|`registrationId`
|`spring.security.oauth2.client.registration._[registrationId]_.client-id`
|`clientId`
|`spring.security.oauth2.client.registration._[registrationId]_.client-secret`
|`clientSecret`
|`spring.security.oauth2.client.registration._[registrationId]_.client-authentication-method`
|`clientAuthenticationMethod`
|`spring.security.oauth2.client.registration._[registrationId]_.authorization-grant-type`
|`authorizationGrantType`
|`spring.security.oauth2.client.registration._[registrationId]_.redirect-uri`
|`redirectUriTemplate`
|`spring.security.oauth2.client.registration._[registrationId]_.scope`
|`scopes`
|`spring.security.oauth2.client.registration._[registrationId]_.client-name`
|`clientName`
|`spring.security.oauth2.client.provider._[providerId]_.authorization-uri`
|`providerDetails.authorizationUri`
|`spring.security.oauth2.client.provider._[providerId]_.token-uri`
|`providerDetails.tokenUri`
|`spring.security.oauth2.client.provider._[providerId]_.jwk-set-uri`
|`providerDetails.jwkSetUri`
|`spring.security.oauth2.client.provider._[providerId]_.user-info-uri`
|`providerDetails.userInfoEndpoint.uri`
|`spring.security.oauth2.client.provider._[providerId]_.user-info-authentication-method`
|`providerDetails.userInfoEndpoint.authenticationMethod`
|`spring.security.oauth2.client.provider._[providerId]_.userNameAttribute`
|`providerDetails.userInfoEndpoint.userNameAttributeName`
|===
[[oauth2login-common-oauth2-provider]]
=== CommonOAuth2Provider
`CommonOAuth2Provider` pre-defines a set of default client properties for a number of well known providers: Google, GitHub, Facebook, and Okta.
For example, the `authorization-uri`, `token-uri`, and `user-info-uri` do not change often for a Provider.
Therefore, it makes sense to provide default values in order to reduce the required configuration.
As demonstrated previously, when we <<oauth2login-sample-application-config,configured a Google client>>, only the `client-id` and `client-secret` properties are required.
The following listing shows an example:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
google:
client-id: google-client-id
client-secret: google-client-secret
----
[TIP]
The auto-defaulting of client properties works seamlessly here because the `registrationId` (`google`) matches the `GOOGLE` `enum` (case-insensitive) in `CommonOAuth2Provider`.
For cases where you may want to specify a different `registrationId`, such as `google-login`, you can still leverage auto-defaulting of client properties by configuring the `provider` property.
The following listing shows an example:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
google-login: <1>
provider: google <2>
client-id: google-client-id
client-secret: google-client-secret
----
<1> The `registrationId` is set to `google-login`.
<2> The `provider` property is set to `google`, which will leverage the auto-defaulting of client properties set in `CommonOAuth2Provider.GOOGLE.getBuilder()`.
[[oauth2login-custom-provider-properties]]
=== Configuring Custom Provider Properties
There are some OAuth 2.0 Providers that support multi-tenancy, which results in different protocol endpoints for each tenant (or sub-domain).
For example, an OAuth Client registered with Okta is assigned to a specific sub-domain and have their own protocol endpoints.
For these cases, Spring Boot 2.x provides the following base property for configuring custom provider properties: `spring.security.oauth2.client.provider._[providerId]_`.
The following listing shows an example:
[source,yaml]
----
spring:
security:
oauth2:
client:
registration:
okta:
client-id: okta-client-id
client-secret: okta-client-secret
provider:
okta: <1>
authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
user-name-attribute: sub
jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys
----
<1> The base property (`spring.security.oauth2.client.provider.okta`) allows for custom configuration of protocol endpoint locations.
[[oauth2login-override-boot-autoconfig]]
=== Overriding Spring Boot 2.x Auto-configuration
The Spring Boot 2.x auto-configuration class for OAuth Client support is `OAuth2ClientAutoConfiguration`.
It performs the following tasks:
* Registers a `ClientRegistrationRepository` `@Bean` composed of `ClientRegistration`(s) from the configured OAuth Client properties.
* Provides a `WebSecurityConfigurerAdapter` `@Configuration` and enables OAuth 2.0 Login through `httpSecurity.oauth2Login()`.
If you need to override the auto-configuration based on your specific requirements, you may do so in the following ways:
* <<oauth2login-register-clientregistrationrepository-bean,Register a ClientRegistrationRepository @Bean>>
* <<oauth2login-provide-websecurityconfigureradapter,Provide a WebSecurityConfigurerAdapter>>
* <<oauth2login-completely-override-autoconfiguration,Completely Override the Auto-configuration>>
[[oauth2login-register-clientregistrationrepository-bean]]
==== Register a ClientRegistrationRepository @Bean
The following example shows how to register a `ClientRegistrationRepository` `@Bean`:
[source,java]
----
@Configuration
public class OAuth2LoginConfig {
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("openid", "profile", "email", "address", "phone")
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build();
}
}
----
[[oauth2login-provide-websecurityconfigureradapter]]
==== Provide a WebSecurityConfigurerAdapter
The following example shows how to provide a `WebSecurityConfigurerAdapter` with `@EnableWebSecurity` and enable OAuth 2.0 login through `httpSecurity.oauth2Login()`:
[source,java]
----
@EnableWebSecurity
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
----
[[oauth2login-completely-override-autoconfiguration]]
==== Completely Override the Auto-configuration
The following example shows how to completely override the auto-configuration by registering a `ClientRegistrationRepository` `@Bean` and providing a `WebSecurityConfigurerAdapter`.
[source,java]
----
@Configuration
public class OAuth2LoginConfig {
@EnableWebSecurity
public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
private ClientRegistration googleClientRegistration() {
return ClientRegistration.withRegistrationId("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
.scope("openid", "profile", "email", "address", "phone")
.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
.tokenUri("https://www.googleapis.com/oauth2/v4/token")
.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
.userNameAttributeName(IdTokenClaimNames.SUB)
.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
.clientName("Google")
.build();
}
}
----
[[oauth2login-javaconfig-wo-boot]]
=== Java Configuration without Spring Boot 2.x
If you are not able to use Spring Boot 2.x and would like to configure one of the pre-defined providers in `CommonOAuth2Provider` (for example, Google), apply the following configuration:
[source,java]
----
@Configuration
public class OAuth2LoginConfig {
@EnableWebSecurity
public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
}
@Bean
public OAuth2AuthorizedClientService authorizedClientService(
ClientRegistrationRepository clientRegistrationRepository) {
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository(
OAuth2AuthorizedClientService authorizedClientService) {
return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);
}
private ClientRegistration googleClientRegistration() {
return CommonOAuth2Provider.GOOGLE.getBuilder("google")
.clientId("google-client-id")
.clientSecret("google-client-secret")
.build();
}
}
----
[[oauth2login-resources]]
=== Additional Resources
The following additional resources describe advanced configuration options:
* <<oauth2login-advanced-login-page, OAuth 2.0 Login Page>>
* <<oauth2login-advanced-redirection-endpoint, Redirection Endpoint>>
* <<oauth2login-advanced-userinfo-endpoint, UserInfo Endpoint:>>
** <<oauth2login-advanced-map-authorities, Mapping User Authorities>>
** <<oauth2login-advanced-custom-user, Configuring a Custom OAuth2User>>
** <<oauth2login-advanced-oauth2-user-service, OAuth 2.0 UserService>>
** <<oauth2login-advanced-oidc-user-service, OpenID Connect 1.0 UserService>>