OAuth2 - Google Authorization Server
In previous article, we learned about Basic Authentication , Digest Authentication.In this tutorial, will learn how to configure and use an external Authorization Server.
Spring Boot Security - OAuth 2 Tutorial :
Maven Dependencies
In addition to the Spring Securities dependencies, need to add spring-boot-starter-oauth2-client
and spring-cloud-starter-oauth2
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.techgeeknext</groupId>
<artifactId>security-google-oauth2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>security-google-oauth2</name>
<description>Google Authorization project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Google OAuth Client Registration
- Goto Google Cloud Console, sign in with gmail account credential to register with Google OAuth Server.
- Click on Credentials link -> Click on Create Credentials -> Click on OAuth client ID
- Now, select Application type as "Web Application", and redirect uri as
https://localhost:8083/techgeeknext/login/oauth2/code/google
and click on Create button. - Once it's created, it will generate client id and client secret for the registered web application.
Configure Google OAuth2 Client Properties
Now, add the above generated client id and client secret in application.yml file with database and security properties.
logging:
level:
org.springframework.security: DEBUG
server:
port: 8083
servlet:
context-path: /techgeeknext
session:
cookie:
path: /techgeeknext
ssl:
key-store-password: techgeeknext123
key-store: classpath:securitykeystore.p12
key-store-type: PKCS12
key-alias: techgeeknext-alias
spring:
security:
oauth2:
client:
registration:
google:
client-id: 577562403106-87f3jejmddqoqod1bobg0komj3ttlt3c.apps.googleusercontent.com
client-secret: LOLlu3kbvbAF68t
scope: profile
client-name: TechGeekNextOAuthWebClient
datasource:
url: jdbc:mysql://localhost/SecuritySchema?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: root
platform: mysql
initialization-mode: always
jpa:
hibernate:
ddl-auto: update
Project Structure:
Enable OAuth2 Client Configuration
Now, create configuration class to enable the OAuth2 client for web security.
package com.techgeeknext.security.google.oauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.sql.DataSource;
@Configuration
@Order(1)
@EnableOAuth2Client
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("oauth2authSuccessHandler")
private AuthenticationSuccessHandler oauth2authSuccessHandler;
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login")
.and().csrf().disable()
.logout().logoutUrl("/logout").logoutSuccessUrl("/login")
.and().oauth2Login().loginPage("/login")
.successHandler(oauth2authSuccessHandler);
http.headers().frameOptions().disable();
}
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource).passwordEncoder(getPasswordEncoder());
}
@Bean
public PasswordEncoder getPasswordEncoder() {
DelegatingPasswordEncoder encoder = (DelegatingPasswordEncoder)PasswordEncoderFactories.createDelegatingPasswordEncoder();
return encoder;
}
}
The @EnableOAuth2Client
enables for an OAuth2 client configuration in Spring Web Security application.
The oauth2Login() method was implemented in Spring 5.0. The oauth2Login() method configures support for authentication using the OAuth 2.0 or OpenID Connect 1.0 provider. The default configuration will auto-generate the login page on the /login URL.
Authentication Success Handler
We can manage post-authentication activity by using below methods:
- defaultSuccessUrl() and failureUrl(): It redirect the user to a specified URL.
- successHandler() and failureHandler(): To execute custom logic after the user authentication successful process.
If you notice, we used SuccessHandler and provided custom logic to store user information with dummy password (pass123) in the database if it did not exist.
package com.techgeeknext.security.google.oauth2.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import com.techgeeknext.security.google.oauth2.model.Users;
import com.techgeeknext.security.google.oauth2.repository.UserRepository;
@Component("oauth2authSuccessHandler")
public class Oauth2AuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();;
@Autowired
private OAuth2AuthorizedClientService authorizedClientService;
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder encoder;
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
OAuth2AuthenticationToken authenticationToken = (OAuth2AuthenticationToken) authentication;
String firstName = null;
if (userRepository.findByUsername(authentication.getName()) == null) {
firstName = authenticationToken.getPrincipal().getAttributes().get("given_name").toString();
String email = authenticationToken.getPrincipal().getAttributes().get("email").toString();
Users user = new Users(email, firstName, " ", email, encoder.encode("pass123"), true);
userRepository.save(user);
}
this.redirectStrategy.sendRedirect(request, response,firstName!=null?"/hello?name="+firstName:"/hello");
}
}
Login Page
Provide the link to Authorization server oauth2/authorization/google
in the login page.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>OAuth2 Google Example</title>
</head>
<body>
<h4>Sign-in to your Google Account:</h4>
<form class="form-signin" th:action="@{/login}" method="post">
<button
style="background-color: #7fbefa;"
onclick="location.href='oauth2/authorization/google'"
type="button">
Login with Google
</button>
</form>
</body>
</html>
Take a look at our suggested posts:
REST Controller:
Let's create simple hello rest endpoint for the testing purpose .package com.techgeeknext.security.google.oauth2.controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String sayHello(Model model, @RequestParam(defaultValue = "TechGeekUser" ,required = false)String name) {
model.addAttribute("name", name);
return "Hello "+name;
}
}
Testing OAuth2 through Google Authorization Server
- Access the url https://localhost:8083/techgeeknext/hello, so that it'll redirect to login page.
- Now, click on Login with Google, it will redirect the page to select your google account, and if you notice it has client-id as the part of the url.
- Now, provide your credential and proceed.
- Once login is successful, we can see hello rest end point with it's response, which displays logged in user name.
- Also, you can notice that the user which doesn't exist in database, we store those information in our database from oauth2authSuccessHandler.
Download Source Code
The full source code for this article can be found on below.Download it here - OAuth2 - Google Authorization Server