Book Image

OAuth 2.0 Cookbook

By : Adolfo Eloy Nascimento
Book Image

OAuth 2.0 Cookbook

By: Adolfo Eloy Nascimento

Overview of this book

OAuth 2.0 is a standard protocol for authorization and focuses on client development simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and so on. This book also provides useful recipes for solving real-life problems using Spring Security and creating Android applications. The book starts by presenting you how to interact with some public OAuth 2.0 protected APIs such as Facebook, LinkedIn and Google. You will also be able to implement your own OAuth 2.0 provider with Spring Security OAuth2. Next, the book will cover practical scenarios regarding some important OAuth 2.0 profiles such as Dynamic Client Registration, Token Introspection and how to revoke issued access tokens. You will then be introduced to the usage of JWT, OpenID Connect, and how to safely implement native mobile OAuth 2.0 Clients. By the end of this book, you will be able to ensure that both the server and client are protected against common vulnerabilities.
Table of Contents (16 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface
Index

Accessing OAuth 2.0 Google protected resources bound to the user's session


This recipe presents you with how to retrieve a user's profile from Google Plus, through the user's Google account. This recipe relies on Spring Social to abstract the authorization and the usage of the Google Plus API and tightens the user's Google connection with Spring Security to allow managing connections per logged user.

Getting ready

To run this recipe, create a web application using Spring Boot which will help with the development of the application. To abstract and ease the OAuth 2.0 grant type implementation and help with using Google Plus's API, this recipe also relies on the spring-social-google project and spring-security project.

How to do it...

Follow the steps that basically present you with how to register your application with Google and how to interact with the Google Plus API through the use of the Spring Social Google provider with Spring Security.

  1. Go to the Google Developers Console located at https://console.developers.google.com to start registering the application.
  1. You should see the following screen if you still do not have any project created:
  1. To create a new application, click on Select a project and you will see the following screen:

  1. Therefore, click on the + button to start registering your application and you will see the following interface:
  1. Define the name of your project. I have defined the name social-google1 but you can use any of your preference (but don't forget to change all references to this name throughout the recipe). Then, after setting the name, just click on Create and you will be redirected to the dashboard of your new application as presented in the following screenshot:

  1. Now, to be able to retrieve a user's profile, you must enable an API which in the case of this recipe will be the Google Plus API. Click on the ENABLE API link or on Library at the left side of the dashboard presented in the previous screenshot to see the following Google API portfolio:
  1. Then select Google+ API by searching through the Search all input text, or by clicking on the link presented in the Libraries page as follows:

  1. Click on the ENABLE link at the top of the page as presented in the following screenshot:
  1. After enabling the API, you need to create OAuth 2.0 credentials to be able to interact with the Google Plus API, so you must click on Credentials at the left side of the panel:

  1. Click on Create credentials and select the OAuth client ID as follows:
  1. Select the Application Type which must be Web application for this recipe:

  1. Then enter the URL settings for JavaScript origins and Authorized redirect URIs, as presented in the following screenshot:
  1. Click on Create and grab the client ID and client secret that will be prompted by Google as follows:
  1. Now, you have all that's needed to create a social-google1 project.
  1. Create the initial project using Spring Initializr as we did for other recipes in this book. Go to https://start.spring.io/ and define the following data:
    • Set up the group as com.packt.example.
    • Define the Artifact as social-google1(you can use different names if you prefer, but do not forgot to change all the references tosocial-google1used throughout this recipe).
    • Add Web,ThymeleafandSecurityas the dependencies for this project.
  2. Import the project to your IDE (if using Eclipse, import as a Maven Project).
  3. Open the pom.xml file and add the following dependencies:
<dependency> 
   <groupId>org.springframework.social</groupId> 
   <artifactId>spring-social-google</artifactId> 
   <version>1.0.0.RELEASE</version> 
</dependency> 
<dependency> 
   <groupId>org.springframework.social</groupId> 
   <artifactId>spring-social-security</artifactId> 
</dependency> 
  1. Create the class GoogleProperties within the package com.packt.example.socialgoogle1.config and add the following content:
@ConfigurationProperties("spring.social.google") 
public class GoogleProperties { 
   private String appId; 
   private String appSecret; 
 
   public String getAppId() { return this.appId; }
   public void setAppId(String appId) { this.appId = appId; } 
   public String getAppSecret() { return this.appSecret; } 
   public void setAppSecret(String appSecret) { this.appSecret = appSecret; } 
} 
  1. Now add the respective attributes within the file application.properties which maps to the attributes defined in the GoogleProperties class (change the credentials to those received when registering the application):
spring.social.google.appId=688645170704 
spring.social.google.appSecret=OIRTUxhs
  1. Create the class GoogleConfigurerAdapter inside com.packt.example.socialgoogle1.config with the following content:
@Configuration @EnableSocial 
@EnableConfigurationProperties(GoogleProperties.class) 
public class GoogleConfigurerAdapter extends SocialConfigurerAdapter { 
   @Autowired 
   private GoogleProperties properties; 
} 
  1. Now add the following method to configure the ConnectionFactory for the Google provider (this method must be declared inside GoogleConfigurerAdapter):
@Override 
public void addConnectionFactories(ConnectionFactoryConfigurer configurer, 
   Environment environment) { 
   GoogleConnectionFactory factory =  new GoogleConnectionFactory( 
      this.properties.getAppId(), this.properties.getAppSecret()); 
   configurer.addConnectionFactory(factory); 
} 
  1. Add the following method to declare the bean responsible for providing the (DSL) Domain Specific Language for Google API (when importing the Scope class, import it from org.springframework.context.annotation package and the Connection class, you must import from org.springframework.social.connect package):
@Bean 
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) 
public Google google(final ConnectionRepository repository) { 
   final Connection<Google> connection = repository.findPrimaryConnection(Google.class); 
   return connection != null ? connection.getApi() : null; 
} 
  1. As per the documentation of Spring Social, we need to configure the ConnectionRepository bean using a Session scope, or in other words, a ConnectionRepository must be created on a per user basis. To do so, add the following two method declarations inside GoogleConfigurerAdapter:
@Override 
public UsersConnectionRepository getUsersConnectionRepository( 
         ConnectionFactoryLocator connectionFactoryLocator) { 
   return new InMemoryUsersConnectionRepository(connectionFactoryLocator); 
} 
 
@Override 
public UserIdSource getUserIdSource() { 
   return new AuthenticationNameUserIdSource(); 
} 
  1. Now, as the class AuthenticationNameUserIdSource retrieves the logged user from the Spring Security context, you need to configure Spring Security, defining how to protect the application as well as declaring how to authenticate users. Create the class SecurityConfiguration within the package com.packt.example.socialgoogle1.security, containing the following initial code:
@EnableWebSecurity 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 
} 
  1. Then add the following method inside SecurityConfiguration to define what should be protected, what does not need to be protected, and how the authentication must be performed (which is defined to use form basis authentication):
@Override 
protected void configure(HttpSecurity http) throws Exception { 
   http.authorizeRequests() 
         .antMatchers("/connect/google?*").permitAll() 
         .anyRequest().authenticated().and() 
         .formLogin().and() 
         .logout().permitAll().and() 
         .csrf().disable(); 
}
  1. And to declare some predefined users, add the following method to SecurityConfiguration.
@Override 
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
   auth.inMemoryAuthentication() 
         .withUser("adolfo").password("123").authorities("USER") 
         .and() 
         .withUser("jujuba").password("123").authorities("USER"); 
}
  1. Therefore, create the main controller that decides when to redirect a user to the provider's authentication and authorization page and which retrieves the user's profile by interacting with the Google Plus API. Create the class GooglePlusController inside thecom.packt.example.socialgoogle1 package as presented in the following code:
@Controller 
public class GooglePlusController { 
   @Autowired 
   private Google google; 
   @Autowired 
   private ConnectionRepository connectionRepository; 
 
   @GetMapping 
   public String profile(Model model) { 
         if (connectionRepository 
               .findPrimaryConnection(Google.class) == null) { 
               return "redirect:/connect/google"; 
         } 
 
         String name = google.plusOperations() 
               .getGoogleProfile() 
               .getDisplayName(); 
         model.addAttribute("name", name); 
 
         return "profile"; 
   } 
}
  1. Now let's start creating all the views, primarily defining profile.html inside the templates directory, which resides within the src/main/resources project directory. Add the following content to profile.html:
<!DOCTYPE html> 
<html xmlns:th="http://www.thymeleaf.org"> 
<head> 
<title>LinkedIn integration</title> 
</head> 
<body> 
   <h3> 
         Hello, <span th:text="${name}">User</span>! 
   </h3> 
   <br /> 
</body> 
</html>
  1. Create the googleConnect.html and googleConnected.html files inside templates/connect as presented in the following screenshot:
  1. Add the following content to googleConnect.html:
<html> 
<head> 
<title>Social Google+</title> 
</head> 
<body> 
   <h2>Connect to Google+ to see your profile</h2> 
 
   <form action="/connect/google" method="POST"> 
         <input type="hidden" name="scope" 
           value="https://www.googleapis.com/auth/plus.me" /> 
         <div class="formInfo"> 
           Click the button to share your profile with 
           <b>google plus</b> 
         </div> 
         <p> 
           <button type="submit">Connect to Google</button> 
         </p> 
   </form> 
</body> 
</html> 
  1. Add the following content to googleConnected.html:
<html> 
   <head><title>Social Google Plus</title></head> 
   <body> 
         <h2>Connected to Google</h2> 
         <p>Click <a href="/">here</a> to see your profile.</p> 
   </body> 
</html>
  1. Now the application is ready to be executed. Start the application and go to http://localhost:8080 to start the authorization process to interact with the Google Plus API.

How it works...

An important thing that we did for this recipe was to bind the application users to their respective connection with the OAuth 2.0 Provider (Google in this case). It's important because by doing so, we have a connection per user, unlike the other recipes using Spring Social. But instead of allowing users to register themselves to the social-google1 application, we are using an in-memory model using pre-defined user credentials, as presented in the following code:

auth.inMemoryAuthentication() 
   .withUser("adolfo").password("123").authorities("USER") 
   .and() 
   .withUser("jujuba").password("123").authorities("USER");

So, when running the application and pointing your browser to http://localhost:8080, you must be prompted by an authentication form, as follows.

Enter one of the credentials we declared within the SecurityConfiguration class and click on the Login button, which will lead you to the following page:

This is the page where you might choose to connect with Google by clicking on Connect to Google, which will redirect you to Google's authentication and authorization form as presented in the following screenshot:

Authenticate yourself and grant all the requested permissions and you will be redirected back to the connected page:

Click on the link here and you will be redirected to the profile's HTML view which will retrieve your name from the Google Plus API. Now, if you go to http://localhost:8080/logout, you will be logged out, as you might expect, and if you try to log in with another user you will have to start a new connection flow proving that you have a connection per logged user.

There's more...

For this recipe, we did not configure the base URL, which must be done to avoid issues when running your application behind a proxy. To do so, you might add the following bean declaration inside GoogleConfigurerAdapter:

@Bean 
public ConnectController connectController( 
      ConnectionFactoryLocator locator, 
      ConnectionRepository repository) { 
 
      ConnectController controller =  
            new ConnectController(locator, repository); 
      controller.setApplicationUrl("http://localhost:8080"); 
      return controller; 
} 

Do not forget to define the same redirect URL for the OAuth 2.0 Provider and to make all the communications through TLS/SSL.

To improve security configurations, you might use a database to store all users and respective credentials being held in a cryptographically manner (these features are provided by Spring Security and can be read about in the official documents at https://projects.spring.io/spring-security/).

See also

  • Preparing the environment
  • Reading the user's contacts from Facebook on the server side
  • Accessing OAuth 2.0 LinkedIn protected resources