For the latest stable version, please use Spring Security 6.2.4!

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.

Configure oauth2Login() with 6.0 defaults
  • 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.

Configure oauth2Login() with 5.8 defaults
  • 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.

ClaimAccessor

The method containsClaim(…​) can be replaced with hasClaim(…​).

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).

ClientRegistration

The method getRedirectUriTemplate() can be replaced with getRedirectUri().

ClientRegistration.Builder

The method redirectUriTemplate(…​) can be replaced with redirectUri(…​).

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 implicit grant type is not recommended and all related support is removed in Spring Security 6.

AuthorizationGrantType

The static field IMPLICIT has no direct replacement.

Use of the implicit grant type is not recommended and all related support is removed in Spring Security 6.

OAuth2AuthorizationResponseType

The static field TOKEN has no direct replacement.

Use of the implicit grant type is not recommended and all related support is removed in Spring Security 6.

OAuth2AuthorizationRequest

The static method implicit() has no direct replacement.

Use of the implicit grant type is not recommended and all related support is removed in Spring Security 6.

Address JwtAuthenticationConverter Deprecation

The method extractAuthorities will be removed. Instead of extending JwtAuthenticationConverter, please supply a custom granted authorities converter with JwtAuthenticationConverter#setJwtGrantedAuthoritiesConverter.