For the latest stable version, please use Spring Security 6.4.1! |
OAuth Migrations
The following steps relate to changes around how to configure OAuth 2.0.
Change Default oauth2Login()
Authorities
In Spring Security 5, the default GrantedAuthority
given to a user that authenticates with an OAuth2 or OpenID Connect 1.0 provider (via oauth2Login()
) is ROLE_USER
.
See Mapping User Authorities for more information. |
In Spring Security 6, the default authority given to a user authenticating with an OAuth2 provider is OAUTH2_USER
.
The default authority given to a user authenticating with an OpenID Connect 1.0 provider is OIDC_USER
.
These defaults allow clearer distinction of users that have authenticated with an OAuth2 or OpenID Connect 1.0 provider.
If you are using authorization rules or expressions such as hasRole("USER")
or hasAuthority("ROLE_USER")
to authorize users with this specific authority, the new defaults in Spring Security 6 will impact your application.
To opt into the new Spring Security 6 defaults, the following configuration can be used.
-
Java
-
Kotlin
-
XML
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login((oauth2Login) -> oauth2Login
.userInfoEndpoint((userInfo) -> userInfo
.userAuthoritiesMapper(grantedAuthoritiesMapper())
)
);
return http.build();
}
private GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach((authority) -> {
GrantedAuthority mappedAuthority;
if (authority instanceof OidcUserAuthority) {
OidcUserAuthority userAuthority = (OidcUserAuthority) authority;
mappedAuthority = new OidcUserAuthority(
"OIDC_USER", userAuthority.getIdToken(), userAuthority.getUserInfo());
} else if (authority instanceof OAuth2UserAuthority) {
OAuth2UserAuthority userAuthority = (OAuth2UserAuthority) authority;
mappedAuthority = new OAuth2UserAuthority(
"OAUTH2_USER", userAuthority.getAttributes());
} else {
mappedAuthority = authority;
}
mappedAuthorities.add(mappedAuthority);
});
return mappedAuthorities;
};
}
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
oauth2Login {
userInfoEndpoint {
userAuthoritiesMapper = grantedAuthoritiesMapper()
}
}
}
return http.build()
}
private fun grantedAuthoritiesMapper(): GrantedAuthoritiesMapper {
return GrantedAuthoritiesMapper { authorities ->
authorities.map { authority ->
when (authority) {
is OidcUserAuthority ->
OidcUserAuthority("OIDC_USER", authority.idToken, authority.userInfo)
is OAuth2UserAuthority ->
OAuth2UserAuthority("OAUTH2_USER", authority.attributes)
else -> authority
}
}
}
}
<http>
<oauth2-login user-authorities-mapper-ref="userAuthoritiesMapper" ... />
</http>
Opt-out Steps
If configuring the new authorities gives you trouble, you can opt out and explicitly use the 5.8 authority of ROLE_USER
with the following configuration.
-
Java
-
Kotlin
-
XML
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.oauth2Login((oauth2Login) -> oauth2Login
.userInfoEndpoint((userInfo) -> userInfo
.userAuthoritiesMapper(grantedAuthoritiesMapper())
)
);
return http.build();
}
private GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach((authority) -> {
GrantedAuthority mappedAuthority;
if (authority instanceof OidcUserAuthority) {
OidcUserAuthority userAuthority = (OidcUserAuthority) authority;
mappedAuthority = new OidcUserAuthority(
"ROLE_USER", userAuthority.getIdToken(), userAuthority.getUserInfo());
} else if (authority instanceof OAuth2UserAuthority) {
OAuth2UserAuthority userAuthority = (OAuth2UserAuthority) authority;
mappedAuthority = new OAuth2UserAuthority(
"ROLE_USER", userAuthority.getAttributes());
} else {
mappedAuthority = authority;
}
mappedAuthorities.add(mappedAuthority);
});
return mappedAuthorities;
};
}
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
// ...
oauth2Login {
userInfoEndpoint {
userAuthoritiesMapper = grantedAuthoritiesMapper()
}
}
}
return http.build()
}
private fun grantedAuthoritiesMapper(): GrantedAuthoritiesMapper {
return GrantedAuthoritiesMapper { authorities ->
authorities.map { authority ->
when (authority) {
is OidcUserAuthority ->
OidcUserAuthority("ROLE_USER", authority.idToken, authority.userInfo)
is OAuth2UserAuthority ->
OAuth2UserAuthority("ROLE_USER", authority.attributes)
else -> authority
}
}
}
}
<http>
<oauth2-login user-authorities-mapper-ref="userAuthoritiesMapper" ... />
</http>
Address OAuth2 Client Deprecations
In Spring Security 6, deprecated classes and methods were removed from OAuth2 Client. Each deprecation is listed below, along with a direct replacement.
ServletOAuth2AuthorizedClientExchangeFilterFunction
The method setAccessTokenExpiresSkew(…)
can be replaced with one of:
-
ClientCredentialsOAuth2AuthorizedClientProvider#setClockSkew(…)
-
RefreshTokenOAuth2AuthorizedClientProvider#setClockSkew(…)
-
JwtBearerOAuth2AuthorizedClientProvider#setClockSkew(…)
The method setClientCredentialsTokenResponseClient(…)
can be replaced with the constructor ServletOAuth2AuthorizedClientExchangeFilterFunction(OAuth2AuthorizedClientManager)
.
See Client Credentials for more information. |
OidcUserInfo
The method phoneNumberVerified(String)
can be replaced with phoneNumberVerified(Boolean)
.
OAuth2AuthorizedClientArgumentResolver
The method setClientCredentialsTokenResponseClient(…)
can be replaced with the constructor OAuth2AuthorizedClientArgumentResolver(OAuth2AuthorizedClientManager)
.
See Client Credentials for more information. |
OidcClientInitiatedLogoutSuccessHandler
The method setPostLogoutRedirectUri(URI)
can be replaced with setPostLogoutRedirectUri(String)
.
HttpSessionOAuth2AuthorizationRequestRepository
The method setAllowMultipleAuthorizationRequests(…)
has no direct replacement.
AuthorizationRequestRepository
The method removeAuthorizationRequest(HttpServletRequest)
can be replaced with removeAuthorizationRequest(HttpServletRequest, HttpServletResponse)
.
AbstractOAuth2AuthorizationGrantRequest
The constructor AbstractOAuth2AuthorizationGrantRequest(AuthorizationGrantType)
can be replaced with AbstractOAuth2AuthorizationGrantRequest(AuthorizationGrantType, ClientRegistration)
.
ClientAuthenticationMethod
The static field BASIC
can be replaced with CLIENT_SECRET_BASIC
.
The static field POST
can be replaced with CLIENT_SECRET_POST
.
OAuth2AccessTokenResponseHttpMessageConverter
The field tokenResponseConverter
has no direct replacement.
The method setTokenResponseConverter(…)
can be replaced with setAccessTokenResponseConverter(…)
.
The field tokenResponseParametersConverter
has no direct replacement.
The method setTokenResponseParametersConverter(…)
can be replaced with setAccessTokenResponseParametersConverter(…)
.
NimbusAuthorizationCodeTokenResponseClient
The class NimbusAuthorizationCodeTokenResponseClient
can be replaced with DefaultAuthorizationCodeTokenResponseClient
.
NimbusJwtDecoderJwkSupport
The class NimbusJwtDecoderJwkSupport
can be replaced with NimbusJwtDecoder
or JwtDecoders
.
ImplicitGrantConfigurer
The class ImplicitGrantConfigurer
has no direct replacement.
Use of the |
AuthorizationGrantType
The static field IMPLICIT
has no direct replacement.
Use of the |
Address JwtAuthenticationConverter
Deprecation
The method extractAuthorities
will be removed.
Instead of extending JwtAuthenticationConverter
, please supply a custom granted authorities converter with JwtAuthenticationConverter#setJwtGrantedAuthoritiesConverter
.