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.
The following code shows an example:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .authorizationEndpoint() ... .redirectionEndpoint() ... .tokenEndpoint() ... .userInfoEndpoint() ... } }
The main goal of the oauth2Login()
DSL was to closely align with the naming, as defined in the specifications.
The OAuth 2.0 Authorization Framework defines the Protocol Endpoints as follows:
The authorization process utilizes two authorization server endpoints (HTTP resources):
As well as one client endpoint:
The OpenID Connect Core 1.0 specification defines the 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. 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:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .clientRegistrationRepository(this.clientRegistrationRepository()) .authorizedClientService(this.authorizedClientService()) .loginPage("/login") .authorizationEndpoint() .baseUri(this.authorizationRequestBaseUri()) .authorizationRequestRepository(this.authorizationRequestRepository()) .and() .redirectionEndpoint() .baseUri(this.authorizationResponseBaseUri()) .and() .tokenEndpoint() .accessTokenResponseClient(this.accessTokenResponseClient()) .and() .userInfoEndpoint() .userAuthoritiesMapper(this.userAuthoritiesMapper()) .userService(this.oauth2UserService()) .oidcUserService(this.oidcUserService()) .customUserType(GitHubOAuth2User.class, "github"); } }
The sections to follow go into more detail on each of the configuration options available:
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 link’s destination for each OAuth Client defaults to the following:
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI
+ "/{registrationId}"
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()
.
The following listing shows an example:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .loginPage("/login/oauth2") ... .authorizationEndpoint() .baseUri("/login/oauth2/authorization") .... } }
Important | |
---|---|
You need to provide a |
Tip | |
---|---|
As noted earlier, configuring The following line shows an example: <a href="/login/oauth2/authorization/google">Google</a> |
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 |
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:
@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(); } }
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. Therefore, the authorization credential is the authorization code. |
The default Authorization Response baseUri
(redirection endpoint) is /login/oauth2/code/*
, which is defined in OAuth2LoginAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI
.
If you would like to customize the Authorization Response baseUri
, configure it as shown in the following example:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .redirectionEndpoint() .baseUri("/login/oauth2/callback/*") .... } }
Important | |
---|---|
You also need to ensure the The following listing shows an example: return CommonOAuth2Provider.GOOGLE.getBuilder("google") .clientId("google-client-id") .clientSecret("google-client-secret") .redirectUriTemplate("{baseUrl}/login/oauth2/callback/{registrationId}") .build(); |
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 | |
---|---|
|
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:
@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(); } }
The UserInfo Endpoint includes a number of configuration options, as described in the following sub-sections:
After the user successfully authenticates with the OAuth 2.0 Provider,
the OAuth2User.getAuthorities()
may be mapped to a new set of GrantedAuthority
instances, which are then supplied to OAuth2AuthenticationToken
.
Tip | |
---|---|
|
In order to map user authorities, you need to provide an implementation of GrantedAuthoritiesMapper
and configure it as shown in the following example:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .userAuthoritiesMapper(this.userAuthoritiesMapper()) ... } private GrantedAuthoritiesMapper userAuthoritiesMapper() { return (authorities) -> { Set<GrantedAuthority> mappedAuthorities = new HashSet<>(); authorities.forEach(authority -> { if (OidcUserAuthority.class.isInstance(authority)) { OidcUserAuthority oidcUserAuthority = (OidcUserAuthority)authority; OidcIdToken idToken = oidcUserAuthority.getIdToken(); OidcUserInfo userInfo = oidcUserAuthority.getUserInfo(); // Map the claims found in idToken and/or userInfo // to one or more GrantedAuthority's and add it to mappedAuthorities } else if (OAuth2UserAuthority.class.isInstance(authority)) { OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority)authority; Map<String, Object> userAttributes = oauth2UserAuthority.getAttributes(); // Map the attributes found in userAttributes // to one or more GrantedAuthority's and add it to mappedAuthorities } }); return mappedAuthorities; }; } }
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
.
The following code demonstrates how you would register a custom OAuth2User
type for GitHub:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .customUserType(GitHubOAuth2User.class, "github") ... } }
The following code shows an example of a custom OAuth2User
type for GitHub:
public class GitHubOAuth2User implements OAuth2User { private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_USER"); private Map<String, Object> attributes; private String id; private String name; private String login; private String email; @Override public Collection<? extends GrantedAuthority> getAuthorities() { return this.authorities; } @Override public Map<String, Object> getAttributes() { if (this.attributes == null) { this.attributes = new HashMap<>(); this.attributes.put("id", this.getId()); this.attributes.put("name", this.getName()); this.attributes.put("login", this.getLogin()); this.attributes.put("email", this.getEmail()); } return attributes; } public String getId() { return this.id; } public void setId(String id) { this.id = id; } @Override public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String getLogin() { return this.login; } public void setLogin(String login) { this.login = login; } public String getEmail() { return this.email; } public void setEmail(String email) { this.email = email; } }
Tip | |
---|---|
|
DefaultOAuth2UserService
is an implementation of an OAuth2UserService
that supports standard OAuth 2.0 Provider’s.
Note | |
---|---|
|
If the default implementation does not suit your needs, you can define your own implementation of OAuth2UserService
for standard OAuth 2.0 Provider’s.
The following configuration demonstrates how to configure a custom OAuth2UserService
:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .userService(this.oauth2UserService()) ... } private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() { return new CustomOAuth2UserService(); } }
OidcUserService
is an implementation of an OAuth2UserService
that supports OpenID Connect 1.0 Provider’s.
Note | |
---|---|
|
If the default implementation does not suit your needs, you can define your own implementation of OAuth2UserService
for OpenID Connect 1.0 Provider’s.
The following configuration demonstrates how to configure a custom OpenID Connect 1.0 OAuth2UserService
:
@EnableWebSecurity public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2Login() .userInfoEndpoint() .oidcUserService(this.oidcUserService()) ... } private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() { return new CustomOidcUserService(); } }