Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
OAuth 2.0 Cookbook
OAuth 2.0 Cookbook

OAuth 2.0 Cookbook: Protect your web applications using Spring Security

Arrow left icon
Profile Icon Adolfo Eloy Nascimento
Arrow right icon
₱2500.99
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.7 (3 Ratings)
Paperback Oct 2017 420 pages 1st Edition
eBook
₱1399.99 ₱2000.99
Paperback
₱2500.99
Subscription
Free Trial
Arrow left icon
Profile Icon Adolfo Eloy Nascimento
Arrow right icon
₱2500.99
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.7 (3 Ratings)
Paperback Oct 2017 420 pages 1st Edition
eBook
₱1399.99 ₱2000.99
Paperback
₱2500.99
Subscription
Free Trial
eBook
₱1399.99 ₱2000.99
Paperback
₱2500.99
Subscription
Free Trial

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

OAuth 2.0 Cookbook

OAuth 2.0 Foundations

This chapter covers the following recipes:

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

Introduction

The main purpose of this chapter is to help you integrate with popular web applications and social media, although at the same time allow you to get familiarized with the foundational principles of OAuth 2.0 specification.

Before diving into the recipes for several use cases, let's look at the big picture of the most scenarios which will be covered. This will give you the opportunity to review some important concepts about OAuth 2.0 specification so we can stay on the same page with the terminologies used throughout the book.

The preceding diagram shows the four main components of the OAuth 2.0 specification:

  • Resource Owner
  • Authorization Server
  • Resource Server
  • Client

Just to review the purpose of these components, remember that the Resource Owner is the user which delegates authority for third-party applications to use resources on its behalf. The third-party application mentioned is represented by the client which I depicted as Mobile client and Web Client. The user's resources are usually maintained and protected by the Resource Server which might be implemented together with the Authorization Server as a single component, for example. The composition of the Authorization Server and Resource Server are referred to as the OAuth 2.0 Provider to simplify the terminology given to the application which is protected by OAuth 2.0.

Preparing the environment

As most examples are written in Java, we will also need an Integrated Development Environment (IDE) and a good framework to help us write simple web applications (as the OAuth 2.0 protocol was designed for HTTP usage), which will be Spring. To simplify the usage of Spring related technologies, this recipe will help you prepare an application using Spring Boot, providing an example endpoint and how to run this project using Maven.

Getting ready

As I previously mentioned, we will run most of the recipes using the Spring Boot Framework which eases the development of applications based on the Spring Framework. So to run this recipe, you just need an environment where you can download some files from the internet, Java 8 properly configured on your machine, and the CURL tool.

CURL is a tool which allows you to run HTTP requests through the command line. It is available by default in Linux and Mac OS environments, so if you are running the recipes on Windows you should install it first. This tool can be downloaded from https://curl.haxx.se/download.html and to install it, you just have to unpack it and add the path for binaries to the PATH environment variable of Windows.

How to do it...

The following steps describe how to prepare the environment and show how to generate a simple project from the Spring Initializr website which will be executed using the appropriate Maven commands:

  1. Generate a project using Spring Initializr service by visiting https://start.spring.io/. Spring Initializr provides lots of options to start setting up your project, such as if you want to use Maven or Gradle to manage your project dependencies, which version of Spring Boot to use, which dependencies to use, and even changing the language from Java to Groovy or Kotlin.
  2. For this simple test, just use the default values for the project manager, Maven Project, with Java language and version 1.5.7 of the Spring Boot.
  3. At Project Metadata, change the value of the field Group to com.packt.example.
  4. Still on Project Metadata, change the name of the Artifact to simplemvc.
  5. In the Dependencies section, type web and select Full-stack web development with Tomcat and Spring MVC. After selecting the right choice, you will see the tag Web underneath Selected Dependencies as follows:
  1. After setting up all the requirements for this simple example, click on the Generate Project button and your browser will start downloading the ZIP file into your Downloads folder.
  2. After downloading this file, you can unzip it and import it to your IDE just to explore the structure of the created project. For Eclipse users, just import the project as a Maven project.
  1. Open the class SimplemvcApplication and you would see the following code in your IDE:
@SpringBootApplication 
public class SimplemvcApplication { 
   public static void main(String[] args) { 
         SpringApplication.run(SimplemvcApplication.class, args); 
   } 
} 
  1. Let's turn the class SimplemvcApplication into a controller by adding the annotation @Controller as presented in the following code:
@Controller @SpringBootApplication 
public class SimplemvcApplication { 
   public static void main(String[] args) { 
         SpringApplication.run(SimplemvcApplication.class, args); 
   } 
} 
  1. Now that our class is declared as a controller, we can define an endpoint so we can see if the project is running properly. Add the method getMessage as follows, within the class SimplemvcApplication:
@GetMapping("/message") 
public ResponseEntity<String> getMessage() { 
   return ResponseEntity.ok("Hello!"); 
} 
  1. If you want to run your project inside the Eclipse IDE, you should just run the class SimplemvcApplication as a Java application by right-clicking at the class and selecting the menu option Run As | Java Application.
  2. After the application is started you should see something like the following message at the end of the output presented in your console:
Started SimplemvcApplication in 13.558 seconds (JVM running for 14.011) 
  1. Execute the following command to know if your application works properly (just check if the output prints Hello):

         curl "http://localhost:8080/message"
  1. If you would like to use the command line you can also start your application by running the following Maven command (to run the application with Maven through the command line, you must install Maven, as explained in the next sections):
mvn spring-boot:run 
  1. If you don't have Maven installed on your machine, the first thing to do is to start downloading the latest version from https://maven.apache.org/download.cgi which at the time of this writing was apache-maven-3.5.0-bin.tar.gz.
  2. After the file has downloaded, just unpack it into any folder you want and start running Maven commands.
  3. Copy the full path of the Maven directory, which was created when you unpacked the downloaded file from the Maven website. If you are running macOS or Linux, run pwd at the command line to discover the full path.
  4. After that, you must add the path for Maven's directory to the PATH environment variable. If you are using Linux or macOS, create the variable MVN_HOME within the .bash_profile file and append the content of MVN_HOME to the end of the PATH environment variable, as presented in the following code:
MVN_HOME=/Users/{your_user_name}/maven-3.5.0 
export PATH=$PATH:$MVN_HOME/bin 
The file .bash_profile should be found at the user's directory. So, to edit this file, you should open the file /Users/{your_user_name}/.bash_profile, or in a shorter way, by using ~/.bash_profile. If you are using Windows, all the environment variables can be edited through the visual interface.
  1. After editing this file, run the command source ~/.bash_profile to reload all the contents.
  2. To check if Maven is perfectly running on your environment, run the following command:
mvn --version.

See also

How it works...

Because of the usage of Spring Boot we can take advantage of projects like Spring MVC and Spring Security. These Spring projects help us to write web applications, REST APIs, and help us to secure our applications. By using the Spring Security OAuth2 project, for example, we can configure our own OAuth 2.0 Providers in addition, to act like clients. This is important because someone trying to write his own OAuth Provider will have to deal with too many details which could easily lead to an insecure OAuth Provider. Spring Security OAuth2 already addresses the main concerns any developer would have to think about.

In addition, Spring Boot eases the initial steps for the bootstrap of the application. When creating a Spring project without Spring Boot we need to deal with dependencies manually by taking care of possible library conflicts. To solve this problem, Spring Boot has some pre-configured modules provided by starters. As an example of a useful starter, let's consider an application with Spring Data JPA. Instead of declaring all the dependencies for hibernate, entity-manager, and transaction-api, just by declaring spring-boot-starter-data-jpa all the dependencies will be imported automatically.

While starting using Spring Boot, things can still become easier by using the Spring Initializr service provided by Pivotal (the Spring maintainer now).

There's more...

All the examples presented in Java can be imported and executed on any Java IDE, but we will use Eclipse just because it is a large, accepted tool among developers around the world. Although this book presents recipes using Eclipse, you can also stick with your preferred tool if you want.

Nowadays, many projects have been designed using Gradle, but many developers are still used to creating their projects using Maven to manage dependencies and the project itself. So, to avoid trick bugs with IDE plugins or any other kind of issue, the recipes using Spring Boot will be managed by Maven. In addition, Eclipse IDE already comes with a Maven plugin which at the time of writing this book was not true for Gradle. To run projects with Gradle in Eclipse, you must install a specific plugin.

See also

Reading the user's contacts from Facebook on the client side

This recipe will present you with how you can integrate with Facebook using the Implicit grant type which is the better choice for public clients and runs directly on the user's web browser.

Grant types as you may already know, defines different methods for an application to retrieve access tokens from an Authorization Server. A grant type may apply for a given scenario regarding the client type being developed. Just as a reminder, OAuth 2.0 specification defines two types of client types: public and confidential.

Getting ready

To run this recipe, you must create a web application using Spring Boot, which will help the development of the application. In addition, we also need to register our application on Facebook. That's one important step when using OAuth 2.0, because as an OAuth Provider, Facebook needs to know which clients are asking for access token and, of course, the Resource Owner (the user) would want to know who is to be granted access to her profile.

How to do it...

Follow these steps to create a client application to integrate with Facebook using client-side flow from OAuth 2.0:

  1. First of all, remember that you must have a Facebook account, and have to register a new application. Go to https://developers.facebook.com/apps/ and you should see something like this:
  1. Click on Create a New App to start registering your application, and you should see the following interface which allows you to define the name of the application:
  1. Click on Create App ID and you will be redirected to the newly created application's dashboard as follows:
  1. To start using the Facebook's Graph API and retrieve the user's contacts, we first need to select one product from several provided by Facebook. For what we need now, you must click on the Set Up button from the Facebook Login box.
  2. After clicking on Set Up, you must choose one platform, which must be Web for this recipe.
  3. After choosing the Web platform, enter the Site URL for your application. I am using a fictitious URL named http://clientimplicit.test.
  4. After saving the URL of your site, just click on Continue.
  5. Now you are ready to set up the redirection URI for the application by clicking on Settings in the left panel, as follows. As this application isn't running for production, I have set up the redirect URI as http://localhost:8080/callback. Don't forget to save the changes:
  1. Now you can click on Dashboard at the left side of the panel so you can grab the App ID and App Secret, which maps to the client_id and client_secret from OAuth 2.0 specifications respectively.
  2. Copy the App ID and App Secret from the dashboard as represented by the following screenshot as follows, so we can use in the code which comes in the next steps:
  1. Once we have our client registered on Facebook, we are ready to start writing code to retrieve the OAuth 2.0 access token using the Implicit grant type (requesting the access token from the client side).
  2. Create a new web application using Spring Initializr at https://start.spring.io/ and define the following data:
    • Set up the group as com.packt.example
    • Define the artifact as client-implicit
    • Add Web and Thymeleaf as dependencies for this project
  1. Create the file client.html within the folder templates which resides inside the src/main/resources project's directory.
  1. Add the following content within the file client.html:
<!DOCTYPE html> 
<html xmlns:th="http://www.thymeleaf.org"> 
<head><title>Facebook - client side integration</title></head> 
<body> 
   Press the following button to start the implicit flow. 
   <button id="authorize" type="button">Authorize</button> 
   <div id="box"></div> 
</body> 
</html>  
  1. The button we have added to the client.html page does not have any behavior attached. So, to allow the user to start the Implicit grant type flow, add the following JavaScript code after the body tag:
<script 
   src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
<script type="text/javascript" th:inline="javascript"> 
/*<![CDATA[*/ 
$(document).ready(function() { 
   $("#authorize").click(makeRequest); 
}); 
 
function makeRequest() { 
    var auth_endpoint = "https://www.facebook.com/v2.9/dialog/oauth", 
         response_type = "token", 
         client_id = "1948923582021549", 
         redirect_uri = "http://localhost:8080/callback", 
         scope = "public_profile user_friends"; 
  
   var request_endpoint = auth_endpoint + "?" + 
         "response_type=" + response_type + "&" + 
         "client_id=" + client_id + "&" + 
         "redirect_uri=" + encodeURI(redirect_uri) + "&" + 
         "scope=" + encodeURI(scope); 
 
   window.location.href = request_endpoint; 
} 
/*]]>*/ 
</script>
  1. Before starting the application, we need to map a URL pattern so the HTML code we wrote before can be rendered. To do so, open the class ClientImplicitApplication.java and assure your code looks like the following:
@Controller @SpringBootApplication 
public class ClientImplicitApplication { 
    public static void main(String[] args) { 
         SpringApplication.run(ClientImplicitApplication.class, args); 
   } 
 
   @GetMapping("/") 
   public String client() { return "client"; } 
} 
  1. In the previous code, we've mapped the root of our application to the client.html web page. But all of this is now serving the purpose of sending to the user the Authorization Server (in this case Facebook) so she could grant our application access to protected resources (which are her friends). Try to start the application and go to http://localhost:8080/.
  2. Click on the ;Authorize button that will be provided by client.html to start the Implicit grant flow, log in with your Facebook account, and accept the permissions requested by the client-implicit application (make sure that jquery is properly declared inside client.html file).
  3. If you grant all the permissions at the consent user page you shall be redirected to http://localhost:8080/callback URL that was specified at the client registration phase on Facebook. Click on Continue and pay attention to the content received and the URL fragment in the browser's address bar. It should be something like the following:
http://localhost:8080/callback#access_token=EAAbsiSHMZC60BANUwKBDCYeySZCjcBpvFuUO1gXsfTGwWjnZAFTAZBIJB62jdUroAcNuZAVWO24yeqo0iazWYytVgrQ1bgNWI8vm07Ws4ZCHXpGridHfZB6PQ1rzM4BzP29IljgTTuBLZBFQBEnEn2LJiOWJjA8J6Y73BLcjIe2vVMZB9c2GnZBpiK4iZAWEtkTsMEZD&expires_in=7152 
  1. Now we need to extract both the access_token and the expires_in parameters which comes after #character, and start using the Facebook Graph API to retrieve the user's friends.
  1. The first thing we can do is to create another URL mapping through our default controller, which is ClientImplicitApplication. Open this class and add the following method so we can deal with Facebook's redirection:
@GetMapping("/callback") 
public String callback() { return "callback_page"; } 
  1. As we can see, the method callback is returning the callback_page string, which will automatically be mapped to the file callback_page.html. So, let's create this file inside the templates folder which resides in the src/main/resources project directory. At first just add the following HTML content to the callback_page.html file:
<!DOCTYPE html> 
<html> 
<head><title>Insert title here</title></head> 
<body> 
Friends who has also granted client-implicit 
<div id="friends"> 
   <ul></ul> 
</div> 
</body> 
</html> 
  1. After receiving the acces_token as a URL fragment, this file will use JavaScript code to interact with Facebook's graph API to retrieve the user's friends, and will populate the tag <ul> with each friend received within the respective <li> tag. Let's start writing our JavaScript code by adding the following content after the body tag:
<script 
   src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
<script type="text/javascript"> 
/*<![CDATA[*/ 
$(document).ready(function() { 
   var fragment = window.location.hash; 
 }); 
/*]]>*/ 
</script>
  1. As we have the fragment content in the fragment variable, add the following function at the end of the JavaScript code:
function getResponse(fragment) { 
   var attributes = fragment.slice(1).split('&'); 
   var response = {}; 
 
   $(attributes).each(function(idx, attr) { 
         var keyValue = attr.split('='); 
         response[keyValue[0]] = keyValue[1]; 
   }); 
 
   response.hasError = function() { 
         return !response['access_token']; 
   }; 
 
   return response; 
} 
  1. The code presented before creates an object named response which might contain an access_token or error description. Unfortunately, Facebook returns all the error data as URL query parameters instead of using the fragment as per OAuth 2.0's specifications. At least the object returned by the getResponse function can tell if the response has an error.
  2. Now let's update the main JavaScript code to the following. The following code extracts the response from the URL fragment, clears the fragment of the URL as a security measure, and in case of an error, just presents a message to the user through a <div> HTML tag:
$(document).ready(function() { 
   var fragment = window.location.hash; 
   var res = getResponse(fragment); 
   window.location.hash = '_#'; 
    if (res.hasError()) { 
        $("<div>Error trying to obtain user's authorization!</div>").insertBefore('#friends'); 
        return; 
   } 
});
  1. Now let's create the most expected function, which is responsible for using the access_token to interact with the Facebook Graph API. Add the following function at the end of the JavaScript code:
function getFriends(accessToken, callback) { 
   var baseUrl = 'https://graph.facebook.com/v2.9/'; 
   var endpoint = 'me/friends'; 
   var url = baseUrl + endpoint; 
 
   $.ajax({ 
        url: url, 
        beforeSend: function(xhr) { 
            xhr.setRequestHeader("Authorization", "Bearer " + accessToken); 
        }, 
        success: function(result){ 
               var friends = result.data; 
               callback(friends); 
        }, 
        error: function(jqXHR, textStatus, errorThrown)   { 
            console.log(textStatus); 
        } 
    }); 
} 
  1. And to finish, just update the main JavaScript code which is using all the declared functions as follows:
$(document).ready(function() { 
   var fragment = window.location.hash; 
   var res = getResponse(fragment); 
   window.location.hash = '_#'; 
   if (res.hasError()) { 
       $("<div>Error trying to obtain user's authorization!</div>").insertBefore('#friends'); 
       return; 
   } 
   getFriends(res['access_token'], function(friends) { 
       $(friends).each(function(index, friend) { 
           $('#friends').find('ul').append('<li>' + friend.name + '</li>'); 
       }); 
   }); 
}); 
  1. Now it's time to run the client-implicit application to see the usage of OAuth 2.0 and the Facebook Graph API in practice.
  1. Start the application.
  2. Go to http://localhost:8080/ and click on the Authorize button.
  3. Grant the requested permissions.
  4. When you are redirected back to client-implicit, you should see something like the following in your web browser:
  1. As you might notice, your application might not retrieve any users yet. That's because Facebook just allows you to present friends who also authorized your application. In our case, another user should be the client-implicit user and you have to register her as a tester for your application.
When running on Firefox which version is over 42, you must need to disable Tracking Protection that is a feature provided by Firefox to block content loaded from domains that track users across sites).

How it works...

To start using OAuth 2.0's protected resources, before requesting the access_token through the user's grant, we registered the application client-implicit through the OAuth 2.0 Provider (Facebook). The responsibility of maintaining the client's data belongs to the Authorization Server. In using Facebook the boundaries between the Authorization Server and the Resource Server is not so clear. The most important thing to understand here is that Facebook is acting as an OAuth 2.0 Provider.

As per the specifications, we have performed the three important steps in client registration process, which was to choose the client type, register the redirection URI, and enter the application's information.

By registering the application, we've received the client_id and client_secret, but as we are using the Implicit grant flow the client_secret won't be needed. That's because this first recipe presents an application which runs directly on the web browser. So, there is no way to safely protect the client_secret. When not using the client_secret we must try not to expose the received access_token that comes with the URL fragment after the user grants permission to access her resources. Another measure to help the application to not expose the access token was to clear the URL fragment.

Another measure that might be applied is to not use any external JavaScript code as such that was used to send usage metrics (in such a way that the access_token could be sent to the external service).

After the registration process we got into the code to effectively interact with the Facebook Graph API, which at the time of this writing was version 2.9. Facebook offers two ways to log a user with a valid account:

  • By using the Facebook SDK
  • By manually building a login flow

To make the OAuth 2.0 usage explicit, this recipe was written by manually building a login flow. So to start the process of user's authentication and authorization, the client-implicit application builds the URL for the Authorization Server manually as follows:

var request_endpoint = auth_endpoint + "?" + 
   "response_type=" + response_type + "&" + 
   "client_id=" + client_id + "&" + 
   "redirect_uri=" + encodeURI(redirect_uri) + "&" + 
   "scope=" + encodeURI(scope); 
 
window.location.href = request_endpoint; 

After simply redirecting the user to the Authorization Server's endpoint, the flow is transferred to Facebook, which authenticates the user if needed, and the user authorizes whether or not the client application can make use of its resources. Once the user authorizes the client, she is redirected back to the registered redirection URI, which in our case was http://localhost:8080/callback.

When receiving the access_token all we need to do is extract the token from the URL fragment and start using the Facebook Graph API.

There's more...

As an exercise, you might try to use Facebook SDK, which should be simpler to use for abstracting what we did into the SDK's API. Besides, using the SDK or not, one important thing that should be added to our code is the usage of the state parameter to avoid Cross Site Request Forgery (CSRF) attacks.

A CSRF attack allows a malicious user to execute operations in the name of another user (a victim). Regarding web applications, a valid approach to avoid CSRF is to make the client send a variable to the server with some random string which might be checked after receiving it back from the server's response, so the first value and the second (received) must be the same.

Regarding security issues, one other valuable suggestion is to send the access_token to the server side so you don't have to request a new access token on every web page of your application (but take care with the expiration time).

All the recipes that follow in this chapter will be using Spring Social project. For more information about the project, you can read the official documents at https://projects.spring.io/spring-social/.

See also

  • Preparing the environment
  • Reading the user's contacts from Facebook on the server side

Reading the user's contacts from Facebook on the server side

Now you are perfectly familiarized with the Facebook login process and Graph API usage. But to allow for a safer approach to get user authorization to retrieve contacts (or friends) from Facebook, this chapter presents how to use the server side approach which maps directly to the Authorization Code grant type from the OAuth 2.0 specifications.

Getting ready

For this recipe, we need to create a simple web application in the same way we did for client-implicit. As we will develop an application which interacts with Facebook at the server side, we are supposed to write a lot of code. But instead of writing too much code, let's use the Spring Social Facebook project.

There is an important step to perform, similar to what we did for client-implicit; as the application is a Facebook client we need to register a new application.

How to do it...

Follow the steps below to create a client application to integrate with Facebook using the server-side flow from OAuth 2.0:

  1. Go to https://developers.facebook.com/apps/ and add a new application by clicking on Add a New App.
  2. Register a new client application on Facebook with the Display Name social-authcode.
  1. You will be guided to select one Facebook product. So, choose Facebook Login by clicking on Set Up and then choose Web as a platform.
  2. You will be asked to enter the site URL, which might be http://socialauthcode.test/.
  3. After creating the application on Facebook, click on Facebook Login on the left panel to configure a valid redirect URI, which should be http://localhost:8080/connect/facebook.
  4. Click on Dashboard on the left panel so you can retrieve the App ID and App Secret which map to client_id and client_secret, as you may already know, and grab the credentials to use later when implementing the client application.
  5. Now let's 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-authcode
    • Add Web and Thymeleaf as the dependencies for this project
  1. Import the project to your IDE. When using Eclipse, just import it as a Maven project.
  1. Now add the following dependencies into the pom.xml file to add support for Spring Social Facebook:
 <dependency> 
   <groupId>org.springframework.social</groupId> 
   <artifactId>spring-social-config</artifactId> 
</dependency> 
<dependency> 
   <groupId>org.springframework.social</groupId> 
   <artifactId>spring-social-core</artifactId> 
</dependency> 
<dependency> 
   <groupId>org.springframework.social</groupId> 
   <artifactId>spring-social-web</artifactId> 
</dependency> 
<dependency> 
   <groupId>org.springframework.social</groupId> 
   <artifactId>spring-social-facebook</artifactId> 
</dependency> 
  1. Create an HTML file named friends.html inside the templates directory located within src/main/resources, as follows:
  1. Open the file friends.html and add the following content:
<!DOCTYPE html> 
<html xmlns:th="http://www.thymeleaf.org"> 
<head> 
   <title>Friends</title> 
</head> 
<body> 
   <h3>Hello, <span th:text="${facebookProfile.name}">User</span>!</h3> 
   <h4>Your friends which also allowed social-authcode:</h4> 
   <div th:each="friend:${friends}"> 
         <b th:text="${friend.id}">[id]</b> - <b th:text="${friend.name}">[name]</b> 
         <hr/> 
   </div> 
</body> 
</html>
  1. Now, we need URL mapping so the previous HTML file can be rendered. To do this, create a new Java class named FriendsController.java inside the package com.packt.example.socialauthcode, with the following content:
@Controller @RequestMapping("/") 
public class FriendsController { 
    @GetMapping 
    public String friends(Model model) { return "friends"; } 
}  
  1. As you may realize, the template friends.html relies on an object named facebookProfile and another named friends. The object facebookProfile must have the name attribute and the friends object must be a list of objects which have id and name properties. The good news is that we don't have to declare classes for these objects because Spring Social already provides them. We just need to have a valid user connection to start using these objects, so add the following attributes inside the FriendsController class:
@Autowired 
private Facebook facebook; 
@Autowired 
private ConnectionRepository connectionRepository;
  1. With the class ConnectionRepository we can save or retrieve user connections with any provider (only Facebook matters now). Let's take advantage of this class to know if there is any user connected with Facebook and if not, we must redirect the user so she can authorize the social-authcode of the application to retrieve protected resources (her friends). Replace the code from friends method of the FriendsController class with the code presented in the following code:
@GetMapping 
public String friends(Model model) { 
    if (connectionRepository.findPrimaryConnection(Facebook.class) == null) { 
        return "redirect:/connect/facebook"; 
    } 
    return "friends"; 
}
  1. Now, add the following source code after the if block, that checks for a connection. This new block of code will be executed when there is a user connected to Facebook (when importing User and Reference classes, make sure to import from org.springframework.social.facebook.api package):
String [] fields = { "id", "email", "name" }; 
User userProfile = facebook.fetchObject("me", User.class, fields); 
 
model.addAttribute("facebookProfile", userProfile); 
PagedList<Reference> friends = facebook.friendOperations().getFriends(); 
model.addAttribute("friends", friends); 
  1. Although this short method executes all that's needed to retrieve the user's profile and contacts using the Authorization Code grant type, you must create some configuration classes. To better group the configuration classes, create a new package called facebook inside com.packt.example.socialauthcode, which will accommodate the following classes:
  1. Create the class EnhancedFacebookProperties, as presented in the following code, inside the inner package facebook, so we can configure the application properties as client_id and client_secret (don't forget to create the respective getters and setters for each attribute):
@Component 
@ConfigurationProperties(prefix = "facebook") 
public class EnhancedFacebookProperties { 
   private String appId; 
   private String appSecret; 
   private String apiVersion; 
   // getters and setters omitted for brevity 
}
  1. Before continuing creating the other classes, you must configure the appSecret and apiVersion values so the application social-authcode is able to request an access_token. As you may realize, the class EnhancedFacebookProperties is annotated with @ConfigurationProperties which allows for defining the properties inside the application.properties file, as follows:
facebook.app-id=1948923582021549 
facebook.app-secret=1b4b0f882b185094a903e76a661c7c7c 
facebook.api-version=2.9 
  1. Now create the class CustomFacebookServiceProvider, as follows. This class is responsible for creating a custom instance of OAuth2Template allowing us to effectively configure the Facebook API version which at the time of this writing was 2.9:
public class CustomFacebookServiceProvider extends 
         AbstractOAuth2ServiceProvider<Facebook> { 
 
   private String appNamespace; 
   private String apiVersion; 
 
   public CustomFacebookServiceProvider( 
         String appId, String appSecret, String apiVersion) { 
         super(getOAuth2Template(appId, appSecret, apiVersion)); 
         this.apiVersion = apiVersion; 
   } 
 
   private static OAuth2Template getOAuth2Template( 
         String appId, String appSecret, String apiVersion) { 
         String graphApiURL =  
               "https://graph.facebook.com/v" + apiVersion + "/"; 
 
         OAuth2Template template = new OAuth2Template( 
               appId, appSecret, "https://www.facebook.com/v" + apiVersion + "/dialog/oauth", graphApiURL + "oauth/access_token"); 
 
         template.setUseParametersForClientAuthentication(true); 
         return template; 
   } 
 
   @Override 
   public Facebook getApi(String accessToken) { 
         FacebookTemplate template = new FacebookTemplate( 
               accessToken, appNamespace); 
         template.setApiVersion(apiVersion); 
         return template; 
   } 
 
} 
  1. So that the CustomFacebookServiceProvider can be properly created, create the class CustomFacebookConnectionFactory as presented in the following code:
public class CustomFacebookConnectionFactory extends 
   OAuth2ConnectionFactory<Facebook> { 
   public CustomFacebookConnectionFactory(String appId, String appSecret, String apiVersion) { 
      super("facebook", 
           new CustomFacebookServiceProvider(appId, appSecret, apiVersion), 
           new FacebookAdapter()); 
   } 
} 
  1. And finally create the class FacebookConfiguration with the following content:
@Configuration @EnableSocial 
@EnableConfigurationProperties(FacebookProperties.class) 
public class FacebookConfiguration extends SocialAutoConfigurerAdapter { 
   @Autowired 
   private EnhancedFacebookProperties properties; 
 
   @Override 
   protected ConnectionFactory<?> createConnectionFactory() { 
         return new CustomFacebookConnectionFactory(this.properties.getAppId(),
this.properties.getAppSecret(), this.properties.getApiVersion()); } }
  1. If you look at the content of FriendsController, you should see that this class is using an instance of Facebook which provides the API to interact with Facebook Graph API. The instance of Facebook must be created through a Spring bean declared as follows inside the FacebookConfiguration (When importing the Connection class, make sure you import from org.springframework.social.connect package):
@Bean 
@ConditionalOnMissingBean(Facebook.class) 
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) 
public Facebook facebook(ConnectionRepository repository) { 
   Connection<Facebook> connection = repository 
         .findPrimaryConnection(Facebook.class); 
   return connection != null ? connection.getApi() : null; 
} 
  1. As we are using Spring Social, most redirection will be handled by the ConnectController class which is declared by Spring Social. But how does Spring Social know to build the redirect URI? We have not provided the application's domain. By default, Spring Social uses request data to build the redirect URL automatically. But as the application might be deployed behind a proxy, the provider won't be capable of redirecting the user back to the callback URL defined inside ConnectController. To overcome this issue, declare the following method inside the FacebookConfiguration class:
@Bean 
public ConnectController connectController( 
         ConnectionFactoryLocator factoryLocator, 
         ConnectionRepository repository) { 
   ConnectController controller = new ConnectController(factoryLocator, repository); 
   controller.setApplicationUrl("http://localhost:8080"); 
   return controller; 
}
  1. This controller provides all we need to handle OAuth 2.0's authorization flow. It also allows the rendering of two views which by default are named {provider}Connect and {provider}Connected where the provider in this case is facebook. To satisfy both views, create the following HTML files inside the folder templates/connect within the src/main/resources project's directory, as follows:
  1. Now add the following content to facebookConnect.html:
<html> 
<head> 
   <title>Social Authcode</title> 
</head> 
<body> 
   <h2>Connect to Facebook to see your contacts</h2> 
 
   <form action="/connect/facebook" method="POST"> 
         <input type="hidden" name="scope"  
               value="public_profile user_friends" /> 
         <input type="hidden" name="response_type"  
               value="code" /> 
          <div class="formInfo"> 
               Click the button to share your contacts  
               with <b>social-authcode</b> 
         </div> 
         <p><button type="submit">Connect to Facebook</button></p> 
   </form> 
 
</body> 
</html>
  1. And now add the following content to facebookConnected.html:
<html> 
   <head><title>Social Authcode</title></head> 
   <body> 
         <h2>Connected to Facebook</h2> 
         <p>Click <a href="/">here</a> to see your friends.</p> 
   </body> 
</html> 
  1. That's it. Now you can start the application by running the class SocialAuthcodeApplication.

How it works...

This chapter presented you with how to register your application and how to connect with Facebook through the use of the Authorization Code grant type. Because it's a server side flow, it is supposed to be more secure than using the client-side approach (that is, to use the Implicit grant type). But instead of writing the code to handle all the conversations between social-authcode and Facebook (the OAuth 2.0 dance) we are using Spring Social, which provides the ConnectController class which has the capability of starting the authorization flow as well as receiving all callbacks that must be mapped when registering the application.

To better understand how this application works, run the class SocialAuthcodeApplication as Java code and go to http://localhost:8080/ to see the page that will present you with the possibility of connecting to Facebook. Click on Connect to Facebook and you will be redirected to the Facebook authentication page (as per OAuth 2.0's specifications).

After authenticating the user, Facebook presents the user consent page presenting the scope the client application is asking for. Click on continue to grant the requested permission.

After granting permission for public_profile and friend_list scopes, the user must be redirected back to localhost:8080/connect with the authorization code embedded (which will be extracted and validated by ConnectController automatically).

Note that ConnectController will render the facebookConnected view by presenting the following page:

Click on the link here so the application can retrieve the friends which have also authorized social-authcode. You are supposed to see the following page with different content:

There's more...

When registering the application on Facebook, we also configured the redirect URI to be http://localhost:8080/connect. Why not use http://localhost:8080/callback? By using the /connect endpoint, we take advantage of the endpoints defined by ConnectController. If you do not want to use Spring Social, you are supposed to validate the authorization code through the use of state parameters by yourself. When using Spring Social, we also take advantage of callbacks which are particular to the Facebook provider as De-authorize Callback URL's which might be set up in the settings from the Facebook Login product.

Even though we are using Spring Social Facebook we are still creating some classes that are also provided by Spring Social Facebook. As you could realize, the name of some classes begin with Custom. That's because we can customize how to create an instance of OAuth2Template as well as the FacebookTemplate class. It's important because the version supported at the time of this writing was 2.5, which was to be deprecated soon, and that's the version defined inside the Facebook provider for Spring Social.

There is an important thing to be mentioned about the interactions between the client and the OAuth 2.0 Provider, which in this case is Facebook. As you may realize, we are registering the redirect URI without using TLS/SSL. The URI we've registered is HTTP instead of HTTPS. All the recipes in this book are using such an approach just to ease the creation of the examples. Be sure to use HTTPS in production to protect the integrity and confidentiality of data transferred between your application and any other provider.

Another valuable improvement which might be done is to use a Relational Database Management System (RDBMS) to persist connections with providers. As the application does not explicitly define the strategy for connection persistence, Spring Social provides the in-memory version, so whenever you restart your server the user's connections will be lost. If you want to try using a database, you might declare a bean of type JdbcUsersConnectionRepository, and create the following table within the database of your choice:

create table UserConnection (userId varchar(255) not null, 
    providerId varchar(255) not null, 
    providerUserId varchar(255), 
    rank int not null, 
    displayName varchar(255), 
    profileUrl varchar(512), 
    imageUrl varchar(512), 
    accessToken varchar(512) not null, 
    secret varchar(512), 
    refreshToken varchar(512), 
    expireTime bigint, 
    primary key (userId, providerId, providerUserId)); 
create unique index UserConnectionRank on UserConnection(userId, providerId, rank);

To get more details about this, look at Spring Social's official documentation at http://docs.spring.io/spring-social/docs/1.1.4.RELEASE/reference/htmlsingle/#section_establishingConnections.

See also

  • Preparing the environment
  • Reading the user's contacts from Facebook on the client side
  • Accessing OAuth 2.0 Google protected resources bound to user's session

Accessing OAuth 2.0 LinkedIn protected resources

This recipe presents you with how to retrieve a LinkedIn user's profile through the user's authorization using OAuth 2.0 and Spring Social to abstract all Authorization Code grant type from the OAuth 2.0 protocol.

Getting ready

To run this recipe, create a simple web application using Spring Boot which will help the development of the application. To abstract and ease the OAuth 2.0 grant type implementation, and to help in using the LinkedIn API, this recipe also relies on the spring-social-linkedin project.

How to do it...

As described by OAuth 2.0's protocol, the client application must be registered at the Authorization Server which in this case is LinkedIn:

  1. So to satisfy this condition, the first thing to do is to register the application on LinkedIn by accessing https://www.linkedin.com/developer/apps/.
  1. When accessing the previous URL, click on Create Application and you will be redirected to the following page which will ask you for basic information about the application being created:
  1. Unlike many other OAuth 2.0 Providers, LinkedIn requires an application logo as you might have seen in the previous image. LinkedIn also asks for more business data such as the website URL, business email, and business phone.
  1. Fill out the form and click on the Submit button. You will be redirected to the application's dashboard as shown in the following screenshot which presents you with the Authentication Keys and the field to define the redirection URL:
  1. As we are using Spring Social, let's add a Redirect URL which follows the pattern regarding the endpoint which was defined as connect/linkedin. After entering the Redirect URL, click on the Add and then click on Update button.
  2. Now, make sure to grab the Authorization Keys (that is, client_id and client_secret) to use in the application that we will create in the next step.
  1. Create the initial project using Spring Initializr as we did for the 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-linkd (you can use different names if you prefer, but do not forget to change all the references for linkd that were used throughout this recipe)
    • Add Web and Thymeleaf as the dependencies for this project
  2. Import the project to your IDE (if using Eclipse, import as a Maven Project).
  3. Add the following dependency to the pom.xml file:
<dependency> 
   <groupId>org.springframework.boot</groupId> 
   <artifactId>spring-boot-starter-social-linkedin</artifactId> 
</dependency> 
  1. For this recipe, the Spring Social provider implementation already provides a well-defined auto configuration support for Spring Boot. So, it's easier to create the application and just having to worry about the client credential settings. Open the application.properties file and add the following content (using the credentials generated for your application):
spring.social.linkedin.app-id=77a1bnosz2wdm8 
spring.social.linkedin.app-secret=STHgwbfPSg0Hy8bO 
  1. Now create the controller class ProfileController which has the responsibility of retrieving the user's profile through the use of the LinkedIn API. This class should be created within the package com.packt.linkedin.example.sociallinkd.
  2. Make sure the class ProfileController looks like the following:
@Controller 
public class ProfileController { 
   @Autowired 
   private LinkedIn linkedin; 
   @Autowired 
   private ConnectionRepository connectionRepository; 
   @GetMapping 
   public String profile(Model model) { 
       if (connectionRepository.findPrimaryConnection(LinkedIn.class) == null) { 
             return "redirect:/connect/linkedin"; 
       } 
       String firstName = linkedin.profileOperations()
.getUserProfile().getFirstName(); model.addAttribute("name", firstName); return "profile"; } }
  1. As you might expect, the application will be able to retrieve the user's profile only when the user has made the connection between LinkedIn and the social-linkd client application.
  2. So, if there is no connection available, the user will be redirected to /connect/linkedin which is mapped by the ConnectController class from Spring Social. Such an endpoint will redirect the user to the view, defined by the name linkedinConnect which maps directly to the linkedinConnect.html file that might be created under templates/connect directory, located within the src/main/resources project directory as follows:
  1. Looking at the previous screenshot, you can see that there is also linkedinConnected.html, which will be presented when a user's connection is available for the social-linkd application.
  2. All the logic to decide when to present linkedinConnect.html or linkedinConnected.html is defined inside the method connectionStatus from the ConnectController class. The main logic is defined as presented in the following code:
if (connections.isEmpty()) { 
   return connectView(providerId);  
} else { 
   model.addAttribute("connections", connections); 
   return connectedView(providerId);                
}
  1. Add the following HTML content to linkedinConnect.html:
<html> 
<head><title>Social LinkedIn</title></head> 
<body> 
   <h2>Connect to LinkedIn to see your profile</h2> 
    <form action="/connect/linkedin" method="POST"> 
     <input type="hidden" name="scope" value="r_basicprofile" /> 
      <div class="formInfo"> 
       Click the button to share your profile with  
       <b>social-linkedin</b> 
     </div> 
     <p><button type="submit">Connect to LinkedIn</button></p> 
   </form> 
</body> 
</html> 
  1. Now add the following HTML content to linkedinConnected.html:
<html> 
   <head> 
     <title>Social LinkedIn</title> 
   </head> 
   <body> 
     <h2>Connected to LinkedIn</h2> 
     <p>Click <a href="/">here</a> to see your profile.</p> 
   </body> 
</html> 
  1. To present the user's profile, create the file profile.html inside the templates directory with the following content:
<!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. Now that everything is perfectly configured, start the application and go to http://localhost:8080 to start running the authorization flow.

How it works...

This recipe presented you with how you can create an application that interacts with LinkedIn to retrieve the user's profile using OAuth 2.0 protocol. This recipe relies on Spring Social Provider for LinkedIn, which saves us from having to create a controller to deal with OAuth 2.0 callbacks as well as building URLs for authorization and token requests. This recipe differs from other recipes using Spring Social because it presents one provider implementation which support Spring Boot's auto-configuration feature, so we don't need to create any configuration classes.

Besides the fact that a lot of OAuth 2.0's details are abstracted behind Spring Social, all the steps happen when we run the application and start the authorization flow. In fact, as we are using the Authorization Code grant type, the application retrieves the access token through two steps, which are authorization and token request.

To start the authorization flow you must go to http://localhost:8080/ which, in case of being not connected the user's LinkedIn account with the social-linkd application, should be redirected to /connect/linkedin:

The redirection is performed by the method profile from the ProfileController class. As the controller and this method do not define any paths for a request, it will be defined as / by default. As you may notice in the following code, the first thing the method repositories do is to check if the current user has connected her account with the application, which is social-linkedin:

if (connectionRepository.findPrimaryConnection(LinkedIn.class) == null) { 
    return "redirect:/connect/linkedin"; 
} 

The endpoint /connect/linkedin maps directly to the method connectionStatus from the ConnectController class of Spring Social. If there is no connection, this method calls the private method connectView which builds the name {providerId}Connect, which in LinkedIn's case is linkedinConnect. This is exactly the name of the view we created as linkedinConnect.html.

Open the file linkedinConnect.html to see which scope the application is asking for LinkedIn, and you must realize that it is r_basicprofile. All the available scopes defined by LinkedIn should be retrieved by accessing the application dashboard which is present in the section Default Application Permissions.

Back to the page generated by linkedinConnect view, if you click on the Connect to LinkedIn button, you will be redirected to LinkedIn, which will ask you for your credentials and for your consent.

Notice that LinkedIn, unlike many other OAuth 2.0 Providers, asks for permission at the same time it authenticates the user. If you click on Allow Access and send your credentials at the authentication form, social-linkd will receive the authorization code and will use it to retrieve an access token and create the connection for the current user within the application. Then, if there is a connection, the private method connectedView from ConnectController will be called, which will render the following HTML page defined by linkedinConnected.html:

Clicking on the link here, you will then be redirected to the main page, where your profile name will be presented as follows:

There's more...

For this recipe, we didn't create any configuration class. But if you want to define the base URL for callback redirection that happens when using the OAuth 2.0 protocol, you need to create a configuration class to define a custom ConnectController bean, as presented in the following code:

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

By doing such configurations, you avoid issues when the application runs behind a proxy. The redirect URI will be automatically generated using the request info which will be based on the application which might be running behind a proxy. This way, the OAuth 2.0 Provider won't be able to redirect to the right callback URL because it will be hidden by the proxy. The configuration presented previously allows you to define the proxy's URL.

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

See also

  • Preparing the environment
  • Reading the user's contacts from Facebook on the server side
  • Accessing OAuth 2.0 Google protected resources bound to the user's session

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 to social-google1 used throughout this recipe).
    • Add Web, Thymeleaf and Security as 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
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • •Interact with public OAuth 2.0 protected APIs such as Facebook, LinkedIn and Google.
  • •Use Spring Security and Spring Security OAuth2 to implement your own OAuth 2.0 provider
  • •Learn how to implement OAuth 2.0 native mobile clients for Android applications

Description

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.

Who is this book for?

This book targets software engineers and security experts who are looking to develop their skills in API security and OAuth 2.0. Prior programming knowledge and a basic understanding of developing web applications are necessary. As this book's recipes mostly use Spring Security and Spring Security OAuth2, some prior experience with Spring Framework will be helpful.

What you will learn

  • •Use Redis and relational databases to store issued access tokens and refresh tokens
  • •Access resources protected by the OAuth2 Provider using Spring Security
  • •Implement a web application that dynamically registers itself to the Authorization Server
  • •Improve the safety of your mobile client using dynamic client registration
  • •Protect your Android client with Proof Key for Code Exchange
  • •Protect the Authorization Server from invalid redirection
Estimated delivery fee Deliver to Philippines

Standard delivery 10 - 13 business days

₱492.95

Premium delivery 5 - 8 business days

₱2548.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Oct 18, 2017
Length: 420 pages
Edition : 1st
Language : English
ISBN-13 : 9781788295963
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Philippines

Standard delivery 10 - 13 business days

₱492.95

Premium delivery 5 - 8 business days

₱2548.95
(Includes tracking information)

Product Details

Publication date : Oct 18, 2017
Length: 420 pages
Edition : 1st
Language : English
ISBN-13 : 9781788295963
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just ₱260 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just ₱260 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 8,318.97
Spring Security
₱3316.99
Mastering OAuth 2.0
₱2500.99
OAuth 2.0 Cookbook
₱2500.99
Total 8,318.97 Stars icon
Banner background image

Table of Contents

8 Chapters
OAuth 2.0 Foundations Chevron down icon Chevron up icon
Implementing Your Own OAuth 2.0 Provider Chevron down icon Chevron up icon
Using OAuth 2.0 Protected APIs Chevron down icon Chevron up icon
OAuth 2.0 Profiles Chevron down icon Chevron up icon
Self Contained Tokens with JWT Chevron down icon Chevron up icon
OpenID Connect for Authentication Chevron down icon Chevron up icon
Implementing Mobile Clients Chevron down icon Chevron up icon
Avoiding Common Vulnerabilities Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.7
(3 Ratings)
5 star 33.3%
4 star 33.3%
3 star 0%
2 star 33.3%
1 star 0%
Dmitry Jun 11, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
TBH, I like this book. I got everything I was needed
Amazon Verified review Amazon
Cristiana Dec 15, 2017
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
This book is very helpful. It goes through the steps in a simple and efficient manner. I would strongly recommend 'OAuth 2.0 Cookbook' if you want to get started or improve your knowledge in OAuth 2.0.
Amazon Verified review Amazon
Nobody Dec 11, 2017
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
Gross. Unless you plan to deploy with this java Spring framework I doubt you'll find much generally useful here.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact [email protected] with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at [email protected] using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on [email protected] with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on [email protected] within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on [email protected] who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on [email protected] within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela