Example on Spring Boot 2.x

Spring Boot 2.x provides the ability to fully use auto-configuration to configure login via OAuth 2.0.

This section shows how to configure code example for OAuth login 2.0, using Google as the authentication provider, and the following topics are covered:

  • Initial setup

  • Configuring the URI for redirection

  • Configuring the application.yml file

  • Downloading the application

Initial setup

To use Google's OAuth 2.0 authentication system to log in, you must set up a project in the Google API Console to receive OAuth 2.0 credentials.

Follow the instructions at OpenID Connect, starting with the "Set up OAuth 2.0" section.

After completing the "Obtain OAuth 2.0 credentials" instructions, a new OAuth client should appear with the credentials consisting of a client ID and a client secret.

Configuring a redirect URI

The redirect URI is the path in the application to which the end user's user agent is redirected after authenticating with Google and granting access to OAuth client (created in the previous step) on the Consent page.

In the "Set redirect URI" section, make sure that the authorized redirect URIs field is set to localhost:8080/login/oauth2/code/google.

The default redirect URI template is {baseUrl}/login /oauth2/code/{registrationId}. RegistrationId is a unique identifier for ClientRegistration.
If The OAuth client runs behind a proxy server, it is recommended to check the proxy server configuration to ensure that the application has been configured correctly. Also check out the supported URI template variables for redirect-uri.

Configure the application.yml file

Now that you have a new one OAuth client via Google, you need to configure your application to use an OAuth client for the authentication flow. To do this:

  1. Go to application.yml and set the following configuration:

    spring:
      security:
        oauth2:
          client:
            registration: 
              google: 
                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. The base property prefix is followed by identifier for ClientRegistration, for example google.
  2. Replace the values in the client-id and client-secret properties to the OAuth 2.0 credentials that were created earlier.

Downloading the application

Run the Spring Boot 2.x example and go to localhost:8080. You will then be redirected to an automatically generated standard login page that displays a link for Google.

Click on the Google link and you will be redirected to Google to authenticate.

After authenticate with your Google account credentials, the Consent screen appears on the next page. The Consent screen will ask you to allow or deny access to the OAuth client that was created earlier. Click Allow to allow the OAuth client to access your email address and basic profile information.

At this point, the OAuth client receives your email address and basic profile information. profile from the UserInfo endpoint and establishes an authenticated session.

Property mappings in Spring Boot 2.x

The following table describes the mapping of Spring Boot 2.x OAuth Client properties to 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

redirectUri

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].issuer-uri

providerDetails.issuerUri

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].user-name-attribute

providerDetails.userInfoEndpoint.userNameAttributeName

ClientRegistration can be initially configured using configuration endpoint of the OpenID Connect provider or Authorization server metadata endpoint by setting the property spring.security.oauth2.client.provider.[providerId].issuer-uri.

CommonOAuth2Provider

CommonOAuth2Provider predefines a set of standard client properties for a number of well-known providers: Google, GitHub, Facebook and Okta.

For example, authorization-uri, token-uri and user-info-uri do not change frequently for any given provider. Therefore, it makes sense to provide default values to reduce the required configuration.

As we showed earlier when we configured the Google client, only the client-id and client-secret properties are required.

The following listing is an example:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: google-client-id
            client-secret: google-client-secret
Automatic detection of standard client properties works without problems here, since registrationId (google) matches enum GOOGLE (case insensitive) in CommonOAuth2Provider.

For cases where you need to set a different registrationId, for example google-login, you can still use automatic detection of default client properties by configuring the propertyprovider.

The following listing is an example:

spring:
  security:
    oauth2:
      client:
        registration:
          google-login: 
            provider: google	
            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 allow the automatic detection of default client properties set in CommonOAuth2Provider.GOOGLE.getBuilder().

Configuring custom provider properties

Some OAuth 2.0 providers support shared tenancy, which results in the creation of different endpoints protocols for each tenant (or subdomain).

For example, an OAuth client registered with Okta is assigned to a specific subdomain and has its own protocol endpoints.

For such cases, Spring Boot 2 .x provides the following basic property for configuring custom provider properties: spring.security.oauth2.client.provider.[providerId].

The following listing is an example:

spring:
  security:
    oauth2:
      client:
        registration:
          okta:
            client-id: okta-client-id
            client-secret: okta-client-secret
        provider:
          okta:	
            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. Base property (spring.security.oauth2.client.provider.okta) allows you to custom configure the location of protocol endpoints.

Spring Boot 2.x autoconfiguration override

Spring Boot 2.x autoconfiguration class for OAuth client support – OAuth2ClientAutoConfiguration.

It performs the following tasks:

  • Registers @Bean for ClientRegistrationRepository consisting of ClientRegistration instance(s) of configured OAuth client properties.

  • Registers a @Bean for SecurityFilterChain and activates authorization in OAuth 2.0 via httpSecurity.oauth2Login().

If you need to override auto-configuration for specific needs , then you can do this in the following ways:

  • Register @Bean for ClientRegistrationRepository

  • Register @Bean for SecurityFilterChain

  • Full auto-config override

Registering @Bean for ClientRegistrationRepository

The following example shows how to register @Bean for ClientRegistrationRepository:

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.CLIENT_SECRET_BASIC)
			.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
			.redirectUri("{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();
	}
}
Kotlin

@Configuration
class OAuth2LoginConfig {
    @Bean
    fun clientRegistrationRepository(): ClientRegistrationRepository {
        return InMemoryClientRegistrationRepository(googleClientRegistration())
    }
    private fun googleClientRegistration(): ClientRegistration {
        return ClientRegistration.withRegistrationId("google")
                .clientId("google-client-id")
                .clientSecret("google-client-secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("{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()
    }
}

Registering @Bean for SecurityFilterChain

The following example shows how to register @Bean for SecurityFilterChain using the @EnableWebSecurity annotation and enable authorization in OAuth 2.0 via httpSecurity.oauth2Login():

OAuth2 login configuration
Java

@EnableWebSecurity
public class OAuth2LoginSecurityConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			)
			.oauth2Login(withDefaults());
		return http.build();
	}
}
Kotlin

@EnableWebSecurity
class OAuth2LoginSecurityConfig {
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2Login { }
        }
        return http.build()
    }
}

Full auto-configuration override

The following example shows how to completely override autoconfiguration by registering @Bean for ClientRegistrationRepository and @Bean for SecurityFilterChain.

Autoconfiguration override
Java

@Configuration
public class OAuth2LoginConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			)
			.oauth2Login(withDefaults());
		return http.build();
	}
	@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.CLIENT_SECRET_BASIC)
			.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
			.redirectUri("{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();
	}
}
Kotlin

@Configuration
class OAuth2LoginConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2Login { }
        }
        return http.build()
    }
    @Bean
    fun clientRegistrationRepository(): ClientRegistrationRepository {
        return InMemoryClientRegistrationRepository(googleClientRegistration())
    }
    private fun googleClientRegistration(): ClientRegistration {
        return ClientRegistration.withRegistrationId("google")
                .clientId("google-client-id")
                .clientSecret("google-client-secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("{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()
    }
}

Java-based configuration without Spring Boot 2.x

If using Spring Boot 2.x is not possible, but you need to configure one of the predefined providers in CommonOAuth2Provider (eg Google), apply the following configuration:

OAuth2 Login Configuration
Java

@EnableWebSecurity
public class OAuth2LoginConfig {
	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			.authorizeHttpRequests(authorize -> authorize
				.anyRequest().authenticated()
			)
			.oauth2Login(withDefaults());
		return http.build();
	}
	@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();
	}
}
Kotlin

@EnableWebSecurity
open class OAuth2LoginConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeRequests {
                authorize(anyRequest, authenticated)
            }
            oauth2Login { }
        }
        return http.build()
    }
    @Bean
    open fun clientRegistrationRepository(): ClientRegistrationRepository {
        return InMemoryClientRegistrationRepository(googleClientRegistration())
    }
    @Bean
    open fun authorizedClientService(
        clientRegistrationRepository: ClientRegistrationRepository?
    ): OAuth2AuthorizedClientService {
        return InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository)
    }
    @Bean
    open fun authorizedClientRepository(
        authorizedClientService: OAuth2AuthorizedClientService?
    ): OAuth2AuthorizedClientRepository {
        return AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService)
    }
    private fun googleClientRegistration(): ClientRegistration {
        return CommonOAuth2Provider.GOOGLE.getBuilder("google")
            .clientId("google-client-id")
            .clientSecret("google-client-secret")
            .build()
    }
}
Xml

<http auto-config="true">
	<intercept-url pattern="/**" access="authenticated"/>
	<oauth2-login authorized-client-repository-ref="authorizedClientRepository"/>
</http>
<client-registrations>
	<client-registration registration-id="google"
                         client-id="google-client-id"
                         client-secret="google-client-secret"
                         provider-id="google"/>
</client-registrations>
<b:bean id="authorizedClientService"
        class="org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService"
        autowire="constructor"/>
<b:bean id="authorizedClientRepository"
        class="org.springframework.security.oauth2.client.web.AuthenticatedPrincipalOAuth2AuthorizedClientRepository">
	<b:constructor-arg ref="authorizedClientService"/>
</b:bean>