📖
Maissen's Grimoire
  • Maissen's Grimoire
  • Html and css grimoire
    • HTML5 Periodical Table
    • HTML Cheat Sheet
    • CSS Cheatsheets
  • Javascript Grimoire
    • JavaScript Cheat Sheet
      • Javascript Array in depth
      • Tagged Template Literals
      • Guard Clauses - The Best Way To Write Complex Conditional Logic
      • JavaScript Optional Chaining
      • JavaScript Null Coalesce
      • What Are Magic Numbers And Why Are They Bad
      • ES6/ECMAScript2015 Cheatsheet
      • First-class and Higher Order Functions: Effective Functional JavaScript
    • Useful JavaScript Tips, Tricks and Best Practices
    • Bits of code
    • Useful JavaScript libraries
      • Components
      • Animation
      • Maps
      • Helpers
      • Presentations
      • Charts
      • Games
      • Audio
      • Images
      • Video
    • Js the right way
  • Angular Grimoire
    • Angular doc
    • Getting Started
    • Angular clean architecture
    • Angular Cheat Sheet
    • TypeScript Cheat Sheet
    • My Favorite Tips and Tricks in Angular
    • NgRx: tips & tricks
    • Bits of code
      • Execute Multiple HTTP Requests in Angular
      • Authentification
        • Angular 8 JWT Authentication with HttpInterceptor and Router
      • Integrations
        • Spring Boot
          • Rest Example
            • Angular,Spring Boot,Spring Data and Rest Example(CRUD)
          • Authentification
            • Angular, Spring Boot: JWT Authentication with Spring Security example
            • Angular Spring Boot Security Oauth2
              • Spring Boot OAUTH2 Role-Based Authorization
              • Spring Boot Security Google Oauth
              • Spring Security OAuth2 User Registration
    • Most used dependency
  • Node Grimoire
    • Express.js 4 Cheatsheet
    • Useful Dependencies
    • How To Use And Write Express Middleware
    • Node.js with SQL databases
      • Node.js Token Based Authentication & Authorization example
      • Node.js Rest APIs example with Express, Sequelize & MySQL
      • Node.js Express & PostgreSQL: CRUD Rest APIs example with Sequelize
      • Sequelize
        • Sequelize Many-to-Many Association example – Node.js & MySQL
        • Sequelize One-to-Many Association example with Node.js & MySQL
    • Node.js with NOSQL databases
      • Node.js + MongoDB: User Authentication & Authorization with JWT
      • Node.js, Express & MongoDb: Build a CRUD Rest Api example
      • MongoDB One-to-One relationship tutorial with Mongoose example
      • MongoDB One-to-Many Relationship tutorial with Mongoose examples
      • MongoDB Many-to-Many Relationship with Mongoose examples
  • Upload files
    • How to upload multiple files in Node.js
    • Upload & resize multiple images in Node.js using Express, Multer, Sharp
    • Upload/store images in MySQL using Node.js, Express & Multer
    • How to upload/store images in MongoDB using Node.js, Express & Multer
  • React Grimoire
    • React Doc
    • React Grimoire
    • React Cheat Sheet
  • spring boot Grimoire
    • Getting started
    • Spring Boot, Spring Data JPA – Rest CRUD API example
    • Spring Boot Token based Authentication with Spring Security & JWT
  • Mongo Grimoire
    • MongoDb-Mongoose Cheat Sheet
  • Development tools
    • Design Patterns
  • maissen_grimoire
Powered by GitBook
On this page
  • Project Structure
  • Spring Security OAuth2 Config
  • Google OAuth2 App Registration
  • Testing Spring Security 5 OAuth2 Default Configuration
  • Spring Security Google OAuth2 Internals
  • Customizing Spring Security oauth2Login()
  • Generating Custom JWT Token
  • Conclusion

Was this helpful?

  1. Angular Grimoire
  2. Bits of code
  3. Integrations
  4. Spring Boot
  5. Authentification
  6. Angular Spring Boot Security Oauth2

Spring Boot Security Google Oauth

PreviousSpring Boot OAUTH2 Role-Based AuthorizationNextSpring Security OAuth2 User Registration

Last updated 5 years ago

Was this helpful?

For a better understanding of spring security OAuth2 internals, We will be building this application with a very basic OAUTH2 integration with default configurations provided by spring security using and then customize it to a greater extent by adding custom login page, custom redirect-uri and UserService, token endpoint etc to extract user details such as name, email and profile image and use this information to generate JWT token out of it to authorize user for future server calls. We will also build an option available for a new user registration using email and password along with google oauth.

In my previous articles, we have discussed a lot about OAuth2 and it's principles and hence I will encourage you to go through those tutorials - first to understand the basics of OAuth2 and then continue here.

Project Structure

Head over to start.spring.io and download a sample spring boot app. Below is the snapshot of mine.

Maven Depenedencies

Apart from the default dependencies that were included during project initialization, we also require below dependencies. pom.xml

<dependency>
	<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.9.0</version>
</dependency>

Spring Security OAuth2 Config

Let us first use the default support provided by spring security 5 for OAuth2 and make our google OAuth sign in process successful as it requires bare minimum configurations. Doing so, we will not get confused after overriding the default implementation and build the final project.

Below is the security config that we require to get started with the OAuth in spring security. oauth2Login() in the below configuration enables all default configurations and makes all the resources protected. Only parameters it requires is the client-id and client-secret which we will be generating on google console in next section.

package com.devglan.springbootgoogleoauth.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .oauth2Login();
    }

}

Now let us implement a test page - index.html. As we have protected all the resources, whenever we try to access index.html, we will be redirected to Google OAuth page and after successful authentication the index.html page will be served by spring boot. index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Dashboard</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width"/>
    <base href="/"/>
    <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
    <script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
    <script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <h1>Welcome !</h1>
</div>
</body>
</html>

Google OAuth2 App Registration

http://localhost:8080/login/oauth2/code/google

as authorised redirect URI on google console.

Once we have the client-id and client-secret, let us configure the same in our application.properties. Below entries in the application.properties is enough to run our application with default configuration. application.properties

spring.security.oauth2.client.registration.google.clientId=150677252870-78tlj6v2mm653alhodqr9t5br5fu5bs0.apps.googleusercontent.com
spring.security.oauth2.client.registration.google.clientSecret=ZptsDAPoVjn7DzVYbzSDNt1v

spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

Testing Spring Security 5 OAuth2 Default Configuration

Whatever we have implemented above is enough to get started with a spring boot OAuth2 application. Spring boot has really made OAuth2 implementation very simple in a spring MVC app. Now, we can run SpringBootGoogleOauthApplication.java as a java application to test the application.

1. Hit localhost:8080/login or localhost:8080 and you will be forwarded to google sign in.

2. Now you can login to google(provider) and authorise this app.

3. Now you can see the index.html page rendered in your browser.

Spring Security Google OAuth2 Internals

The authentication process has been done now and the spring boot configuration looks very simple and straight forward but there are many things that happened in the background. Let us discuss each of them now.

When a request is made to localhost:8080 to access secured resource, spring security does not find any authenticated object in the context and redirects to

http://localhost:8080/oauth2/authorization/google

Now the request is redirected to

accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=150677252870-78tlj6v2mm653alhodqr9t5br5fu5bs0.apps.googleusercontent.com&scope=openid+profile+email&state=QFWkpSxvN-zs5gGoMCnFGDJDTYF1HZg1FC_5l31H0qg%3D&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin%2Foauth2%2Fcode%2Fgoogle.

If you inspect the URL, the url contains the client-id, client-secret and redirect-uri that we configured in the application.properties.

If the redirect_uri that we have configured in application.proprties does not match with the one that we have configured in google console, then you may see an error as Error: redirect_uri_mismatch

https://www.googleapis.com/oauth2/v4/token

to access the user info such as email, picture, name, family_name. Once the response is received by our app, following authentication object will be set in spring security context with ROLE as user and the user will served the secured page index.html page against "/".

Below is a sample response from Google.

Principal: Name: [112360792925347143122], Granted Authorities: [ROLE_USER], User Attributes: [at_hash=TCTreSX3yj6ZB_T3TKTjRg, sub=112360792925347143122, email_verified=true, iss=https://accounts.google.com, given_name=Dhiraj, locale=en-GB, picture=https://lh4.googleusercontent.com/-jf-AkErib08/AAAAAAAAAAI/AAAAAAAAAwc/huSoFQWOXOk/s96-c/photo.jpg, aud=[150677252870-78tlj6v2mm653alhodqr9t5br5fu5bs0.apps.googleusercontent.com], azp=150677252870-78tlj6v2mm653alhodqr9t5br5fu5bs0.apps.googleusercontent.com, name=Dhiraj Ray, exp=2019-01-12T19:16:14Z, family_name=Ray, iat=2019-01-12T18:16:14Z, email=ssss@gmail.com]; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ROLE_USER

Customizing Spring Security oauth2Login()

Custom Redirection Endpoint

The Redirection Endpoint is used by the Authorization Server for returning the Authorization Response to the client. As we discussed above, we are using default redirection endpoint -

http://localhost:8080/login/oauth2/code/google

till now. We can customize it to any other URL of our choice(/oauth2/callback/). Below is the spring security configuration for it. Make sure to update this property in google console and application.properties.

spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/oauth2/callback/google
protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .oauth2Login()
                .redirectionEndpoint()
                .baseUri("/oauth2/callback/*");
    }

Custmomizing userInfoEndpoint()

For Facebook, we need to implement DefaultOAuth2UserService which we will implement in next article. The implenentaion will fetch the user info and creates entry in our local database. And we have already configured our MySql DB support for this app. Below is the implementation.

A call to super() will amke the REST call to fetch the userinfo from the external provider(Google). After a success response, the user entry will be created in our local system. CustomOidcUserService.java

package com.devglan.springbootgoogleoauth.oauth2;

import com.devglan.springbootgoogleoauth.dao.UserRepository;
import com.devglan.springbootgoogleoauth.dto.GoogleOAuth2UserInfo;
import com.devglan.springbootgoogleoauth.model.User;
import com.devglan.springbootgoogleoauth.model.UserType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class CustomOidcUserService extends OidcUserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
        OidcUser oidcUser = super.loadUser(userRequest);
        Map attributes = oidcUser.getAttributes();
        GoogleOAuth2UserInfo userInfo = new GoogleOAuth2UserInfo();
        userInfo.setEmail((String) attributes.get("email"));
        userInfo.setId((String) attributes.get("sub"));
        userInfo.setImageUrl((String) attributes.get("picture"));
        userInfo.setName((String) attributes.get("name"));
        updateUser(userInfo);
        return oidcUser;
    }

    private void updateUser(GoogleOAuth2UserInfo userInfo) {
        User user = userRepository.findByEmail(userInfo.getEmail());
        if(user == null) {
            user = new User();
        }
        user.setEmail(userInfo.getEmail());
        user.setImageUrl(userInfo.getImageUrl());
        user.setName(userInfo.getName());
        user.setUserType(UserType.google);
		userRepository.save(user);
    }
}

Below is our updated security config now.

protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .oauth2Login()
                .redirectionEndpoint()
                .baseUri("/oauth2/callback/*")
                .and()
                .userInfoEndpoint()
                .oidcUserService(oidcUserService);
    }

UserRepository.java

package com.devglan.springbootgoogleoauth.dao;

import com.devglan.springbootgoogleoauth.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository {

    User findByEmail(String email);
}

User.java

@Entity
@Table(name = "User")
public classUser {

    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private int id;
    @Column
    private String name;
    @Column
    private String email;
    @Column
    private String imageUrl;
    @Column
    private UserType userType;
	

Customizing Authorization Endpoint

oauth2Login().authorizationEndpoint() allows configuring the Authorization Endpoint. It is used by the client to obtain authorization from the resource owner via user-agent redirection.

oauth2Login()
.authorizationEndpoint()
                .baseUri("/oauth2/authorize")
                .authorizationRequestRepository(customAuthorizationRequestRepository());
				
@Bean
public AuthorizationRequestRepository customAuthorizationRequestRepository() {
	return new HttpSessionOAuth2AuthorizationRequestRepository();
}

At this point of time, if you try to run this application and follow above steps, you can see a new user entry in the DB.

Customizing Login Endpoint

@Override
protected void configure(HttpSecurity http) throws Exception {
	http
		.oauth2Login()
			.loginPage("/login/oauth2")
			...
			.authorizationEndpoint()
				.baseUri("/oauth2/authorize")
				....
}

Generating Custom JWT Token

@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    @Autowired
    private UserRepository userRepository;

    private String homeUrl = "http://localhost:8080/";

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        if (response.isCommitted()) {
            return;
        }
        DefaultOidcUser oidcUser = (DefaultOidcUser) authentication.getPrincipal();
        Map attributes = oidcUser.getAttributes();
        String email = (String) attributes.get("email");
        User user = userRepository.findByEmail(email);
        String token = JwtTokenUtil.generateToken(user);
        String redirectionUrl = UriComponentsBuilder.fromUriString(homeUrl)
                .queryParam("auth_token", token)
                .build().toUriString();
        getRedirectStrategy().sendRedirect(request, response, redirectionUrl);
    }

}

Below is the implementation for generating JWT token. The implementation of JWT authentication in spring security is very much similar to this - . In next article, we will build the complete implementation of custom login with email and password and JWT token validation.

@Component
public class JwtTokenUtil implements Serializable {

    public static final long ACCESS_TOKEN_VALIDITY_SECONDS = 5*60*60;
    public static final String SIGNING_KEY = "devglan123r";

    public static String generateToken(User user) {
        Claims claims = Jwts.claims().setSubject(user.getEmail());

        return Jwts.builder()
                .setClaims(claims)
                .setIssuer("https://devglan.com")
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_VALIDITY_SECONDS*1000))
                .signWith(SignatureAlgorithm.HS256, SIGNING_KEY)
                .compact();
    }

}

Conclusion

In this article, we implemented spring boot security google oauth and integrated JWT with it.Also, we looked into different ways we can customize the default behaviour of spring security 5 OAuth implementation. In the next article, we will be overriding the default login page and add support for custom login with email and password alng with JWT token validation.

Let us register our app on to get the client-id and cient-secret. As by default spring security 5 redirects user to {baseUrl}/{action}/oauth2/code/google post authentication, we have added

for authentication against oauth2Login() element. This GET request is intercepted by and matches against '/oauth2/authorization/{registrationId} where registrationId in this case is google.

After a successful authentication with google and authorization of our app, the user will be redirected to '/login/oauth2/code/google with the authentication code as request param and this request will be intercepted by . With this auth code, a POST request will be made to

You can visit my another article for a .

Our custom user info endpoint will make request to the provider user info endpoint and retrieve the user info such as name, email, image etc. To do so, we need to implement OAuth2UserService. Spring boot provides two different implementation for this. We will be implementing .

By default, the OAuth 2.0 Login Page is auto-generated by the DefaultLoginPageGeneratingFilter. To override the default login page, configure oauth2Login().loginPage() and to start authentication with Google then you can redirect user to /oauth2/authorize/google. Here, /oauth2/authorize is the authorization endpoint that is configured above. You can visit this article for a

To generate a custom , we require to overide the default AuthenticationSuccessHandler in spring security with our custom success handler. So far, our login process is done and now let us define our success handler. Inside the success handler we will be generating our JWT token.

While generating the JWT token, we will be re-using the features that we had developed in our previous article - . CustomAuthenticationSuccessHandler.java

google developer console
OAuth2AuthorizationRequestRedirectFilter
OAuth2LoginAuthenticationFilter
better understanding of Spring Security filter chain and customization
OidcUserService for OpenID Connect (Google) providers
Spring Security OAuth2 User Registration
JWT (Json Web Token) token
Spring Boot JWT Auth
oauth2Login() element
Spring Security OAuth2