Quick Start: Spring Security 5 OAuth2 Login

Brandon Klimek Development Technology, Security, Spring, Tutorial Leave a Comment

Social logins using Oauth2 have become a industry standard. It has revolutionized the way sites share data and has allowed users to quickly access new applications without having to create a new set of credentials. This article gives an example of why OAuth2 was invented and provides a working example of a Spring Security 5 application integrated with Google.

The source code for this tutorial is available on Github.

So what did sites do before OAuth2?

Before OAuth2, sites did some pretty scary things to get users’ data from other applications, like requiring your login credentials to get your contacts from another application.

The classic example of this is Yelp in 2008 where they asked users for their login credentials to gather their contacts from MSN, Yahoo, AOL, and Gmail. This was a huge security risk because it meant giving your passwords to Yelp with only a promise that they wouldn’t do anything bad to your account.

Example of Yelp before OAuth2

How does OAuth2 solve this problem?

Have you ever created an account on a site using your Facebook, Google, or Microsoft accounts? These are examples of OAuth2 client providers.

Using one of these providers, we can register our application to allow users to sign in with their existing email or social media account while not compromising the security or privacy of the user. Essentially we are off handing all the authentication to the client provider.

Getting Started

With Spring Security 5, this process could not be more simple to implement. In this quickstart tutorial, we will see how to quickly set up a spring boot app that uses Spring Security 5 to authenticate users with Google.

Begin by creating a new Spring Boot project. Because we want this to have a restful interface I am including the “Spring Web” dependencies and of course the “Spring Security” dependency since these give us the OAuth2 client libraries. I am using version 2.2.6.RELEASE for the example.

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- oauth2 -->
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-oauth2-client</artifactId>
	<version>5.3.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-oauth2-jose</artifactId>
	<version>5.3.0.RELEASE</version>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

I also include Swagger dependencies. Swagger is a tool that lets you document your API endpoints. It comes with a nice user interface, and you will see me using this later on to test restful endpoints.

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

Creating an App in Google Cloud

Now that we have all our dependencies setup, we must register our application within the provider (Google Cloud).

The Google OAuth2 implementation follows the OpenID Connect 1.0 specification, which is an identity layer added to the protocol that allows clients to verify the identity of the end-user based on the authentication performed by the authorization server. It provides basic profile information about the end-user.

See Also:  JavaScript Optional Chaining - An Introduction

To authenticate users you must create a new application within the Google Cloud Platform. If you don’t have an account yet, quickly sign up for one. Then navigate to the API & Services -> Credentials section to generate OAuth 2.0 Client Ids.

For this example, I am making this an internal API, which only allows users within my organization to authenticate. I have also set the authorized redirect URI of http://localhost:5000/login/oauth2/code/google.

After creation, you should receive an appId and secret key.

Configuring Google as a Provider within Spring Security 5

Using the newly generated clientId, we will create an Oauth2LoginConfig class within our app.

@Configuration
public class OAuth2LoginConfig {

    @EnableWebSecurity
    public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests(authorize -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; authorize.anyRequest().authenticated())
                    .oauth2Login(Customizer.withDefaults());
        }
    }

    @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("INSERT_APP_ID")
                .clientSecret("INSERT_CLIENT_ID")
                .scope("email",
                        "profile",
                        "openid",
                        "https://www.googleapis.com/auth/user.addresses.read",
                        "https://www.googleapis.com/auth/user.phonenumbers.read",
                        "https://www.googleapis.com/auth/user.birthday.read",
                        "https://www.googleapis.com/auth/user.emails.read")
                .build();
    }
}

This class configuration does several things:

  1. It creates a WebSecurityConfigurerAdapter, which secures all restful endpoints.
  2. It registers a ClientRegistrationRepository and Oauth2AuthorizedClientService, both using there respective in-memory services/repositories. This means that the app will store all user data in memory once logged in.
  3. It provides the Google Client Registration at the bottom – the highlight of this class. Using the API Key and API Secret from our google cloud account, we can update the missing variables. This DSL also configures scopes, which we will request from Google, but the user must approve the scopes to give us access to their profile information.

As mentioned above, this configuration uses a DSL setup. However, if you prefer, you can easily configure the Google Client Registration using a .yml file as well.

What is DSL?

DSL stands for domain-specific language and is also referred to as a fluent interface based on the builder pattern. This is evident by the chaining-together configuration options for the http security and client registration.

Creating a Secure API

At this point, the application is ready to run, but we want to see the results of our authentication with Google.

To do this, create a simple SecureController and output the results of the OAuth2User within the Spring application.

@RestController
public class SecureController {

    @ApiOperation(
            value = "Get the current logged-in user",
            notes = "This example only returns the user logged in from Google")
    @GetMapping("/")
    public HashMap&lt;String, Object&gt; index(@ApiIgnore @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
                                         @ApiIgnore @AuthenticationPrincipal OAuth2User oauth2User) {
        HashMap&lt;String, Object&gt; results = new HashMap&lt;&gt;();
        results.put("username", oauth2User.getName());
        results.put("attributes", oauth2User.getAttributes());
        results.put("authorities", oauth2User.getAuthorities());
        results.put("clientScopes", authorizedClient.getClientRegistration().getScopes());
        results.put("clientName", authorizedClient.getClientRegistration().getClientName());
        return results;
    }
}

See Also:  Decoding Mobile Development Options

What is this RegisteredOAuth2AuthorizedClient and AuthenticationPrincipal?

The RegisteredOAuth2AuthorizedClient annotation resolves to a Oauth2AuthorizedClient, which we have registered in our application using the OAuth2LoginConfig class above.

In this case, it will be Google, and it will resolve to our registered client that has our public and private key. The Oauth2AuthorizedClient also contains the access token, refresh token, and client registration with the user scopes we have requested.

The AuthenticationPrincipal holds our currently authenticated user within the application. It has attributes pertaining to the OpenId 1.0 specification such as name, profile, picture, email, birthdate, etc., which are all considered standard claims.

Swagger Config

Our final step is to create a SwaggerConfig class to register our rest controller location.

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sixthpoint.spring.security.oauth2login.controller"))
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
    }
}

Running the Application

Launch the Spring Boot 2.0 app and go to http://localhost:5000/swagger-ui.html. You are then redirected to a Google for authentication.

After you have authenticated with your Google account credentials, the next page will ask you to consent to your app having access to the Oauth Client registered in your Google Cloud account.

Clicking “allow” will authorize our Spring Boot app to access the users’ email and basic profile information as identified in our scopes from the ClientRegistration.

Once consent has been granted, you will be redirected back to the Swagger UI page. Execute the secure controller get-request to see your authenticate user.

The application currently sets a cookie for an authorized user using a default session called JSESSIONID.

This session is tied to our authenticated user within the application. If I were to restart the application, the in-memory store would be lost. Meaning I would have to log back into the application again.

Wrap Up

Today, this article showed how to quickly get up and running with Spring Security 5 OAuth2. The app integrates with Google to allow for secure authentication and consent of users with a Google account. The applications API was secured using a session token that is generated using the Spring Security 5.3 OAuth2 libraries.

Source code can be found on Github.

Related Posts

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments