Hello and Welcome to the Spring Boot Social Login tutorial series. In this tutorial series, you’ll learn how to add social as well as email and password based login to your spring boot application using the new OAuth2 functionalities provided in Spring Security.

We’ll use MySQL database to store user’s information. For the frontend part, we’ll use React, my favorite Javascript framework.

If you just want the code, you can find it on Github.

Creating the Project

Let’s create our project using Spring Initializr web tool. Head over to http://start.spring.io, fill in the details as follows:

Artifact : spring-social

: spring-social Dependencies: Spring Web, Spring Security, Spring Data JPA, MySQL Driver

You can leave the rest of the fields to their default values and click Generate to generate and download the project -

Directory structure of the complete project for reference

Following is the directory structure of the complete project for your reference. We’ll create all the classes and interfaces one by one and understand their details:

Additional dependencies

We’ll need to add few additional dependencies to our application that are not present in spring initializr web tool. Open the pom.xml file located in the root directory of the project and add the following dependencies -

<!-- OAuth2 Client --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-client</artifactId> </dependency> <!-- JWT library --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.5.1</version> </dependency>

Creating OAuth2 apps for social login

To enable social login with an OAuth2 provider, you’ll need to create an app in the OAuth2 provider’s console and get the ClientId and ClientSecret, sometimes also called an AppId and AppSecret.

OAuth2 providers use the ClientId and ClientSecret to identify your app. The providers also ask for many other settings that include -

Authorized redirect URIs : These are the valid list of redirect URIs where a user can be redirected after they grant/reject permission to your app. This should point to your app endpoint that will handle the redirect.

Scope: Scopes are used to ask users for permission to access their data.

Creating Facebook, Github, and Google Apps

Facebook App : You can create a facebook app from the Facebook apps dashboard

Github App : Github apps can be created from https://github.com/settings/apps.

Google Project: Head over to Google Developer Console to create a Google Project and the credentials for OAuth2.

For the purpose of this article, creating the OAuth2 apps are not mandatory. I have already created a demo app for Facebook, Google, and Github. We’ll use the demo apps to perform social login.

Configuring the Spring Boot application

Spring boot reads configurations from src/main/resource/application.properties file by default. It also supports .yaml configurations. In this project, we’ll use yaml configurations because they represent hierarchical data more clearly.

Rename application.properties file to application.yaml and add the following configurations -

spring: datasource: url: jdbc:mysql://localhost:3306/spring_social?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false username: root password: callicoder jpa: show-sql: true hibernate: ddl-auto: update naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy properties: hibernate: dialect: org.hibernate.dialect.MySQL5InnoDBDialect security: oauth2: client: registration: google: clientId: 5014057553-8gm9um6vnli3cle5rgigcdjpdrid14m9.apps.googleusercontent.com clientSecret: tWZKVLxaD_ARWsriiiUFYoIk redirectUri: "{baseUrl}/oauth2/callback/{registrationId}" scope: - email - profile facebook: clientId: 121189305185277 clientSecret: 42ffe5aa7379e8326387e0fe16f34132 redirectUri: "{baseUrl}/oauth2/callback/{registrationId}" # Note that facebook now mandates the use of https redirect URIs, so make sure your app supports https in production scope: - email - public_profile github: clientId: d3e47fc2ddd966fa4352 clientSecret: 3bc0f6b8332f93076354c2a5bada2f5a05aea60d redirectUri: "{baseUrl}/oauth2/callback/{registrationId}" scope: - user:email - read:user provider: facebook: authorizationUri: https://www.facebook.com/v3.0/dialog/oauth tokenUri: https://graph.facebook.com/v3.0/oauth/access_token userInfoUri: https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture.width(250).height(250) app: auth: tokenSecret: 926D96C90030DD58429D2751AC1BDBBC tokenExpirationMsec: 864000000 oauth2: # After successfully authenticating with the OAuth2 Provider, # we'll be generating an auth token for the user and sending the token to the # redirectUri mentioned by the frontend client in the /oauth2/authorize request. # We're not using cookies because they won't work well in mobile clients. authorizedRedirectUris: - http://localhost:3000/oauth2/redirect - myandroidapp://oauth2/redirect - myiosapp://oauth2/redirect

The datasource configurations are used to connect to the MySQL database. Please create a database named spring_social and specify correct values for spring.datasource.username and spring.datasource.password as per your MySQL installation.

The security.oauth2 configurations define all the oauth2 providers and their details. The app.auth configurations are used to generate a JWT authentication token once the user is successfully logged in.

Notice the use of redirectUriTemplate property in all the registered oauth2 providers. When you create an app in these OAuth2 providers websites, you must add an authorized redirect URI that matches this template. For example, for your google app, you need to add the authorizedRedirectURI http://localhost:8080/oauth2/callback/google .

Binding AppProperties

Let’s bind all the configurations prefixed with app to a POJO class using Spring Boot’s @ConfigurationProperties feature-

package com.example.springsocial.config; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.ArrayList; import java.util.List; @ConfigurationProperties(prefix = "app") public class AppProperties { private final Auth auth = new Auth(); private final OAuth2 oauth2 = new OAuth2(); public static class Auth { private String tokenSecret; private long tokenExpirationMsec; public String getTokenSecret() { return tokenSecret; } public void setTokenSecret(String tokenSecret) { this.tokenSecret = tokenSecret; } public long getTokenExpirationMsec() { return tokenExpirationMsec; } public void setTokenExpirationMsec(long tokenExpirationMsec) { this.tokenExpirationMsec = tokenExpirationMsec; } } public static final class OAuth2 { private List<String> authorizedRedirectUris = new ArrayList<>(); public List<String> getAuthorizedRedirectUris() { return authorizedRedirectUris; } public OAuth2 authorizedRedirectUris(List<String> authorizedRedirectUris) { this.authorizedRedirectUris = authorizedRedirectUris; return this; } } public Auth getAuth() { return auth; } public OAuth2 getOauth2() { return oauth2; } }

Enabling AppProperties

We’ll need to enable configuration properties by adding the @EnableConfigurationProperties annotation. Please open the main application class SpringSocialApplication.java and add the annotation like so-

package com.example.springsocial; import com.example.springsocial.config.AppProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; @SpringBootApplication @EnableConfigurationProperties(AppProperties.class) public class SpringSocialApplication { public static void main(String[] args) { SpringApplication.run(SpringSocialApplication.class, args); } }

Enabling CORS

Let’s enable CORS so that our frontend client can access the APIs from a different origin. I’ve enabled all origins in the following configuration. But you should make it more strict in a production application -

package com.example.springsocial.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final long MAX_AGE_SECS = 3600; @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(MAX_AGE_SECS); } }

Creating the database entities

Let’s now create the Entity classes of our application. Following is the definition of the User class -

package com.example.springsocial.model; import com.fasterxml.jackson.annotation.JsonIgnore; import javax.persistence.*; import javax.validation.constraints.Email; import javax.validation.constraints.NotNull; @Entity @Table(name = "users", uniqueConstraints = { @UniqueConstraint(columnNames = "email") }) public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String name; @Email @Column(nullable = false) private String email; private String imageUrl; @Column(nullable = false) private Boolean emailVerified = false; @JsonIgnore private String password; @NotNull @Enumerated(EnumType.STRING) private AuthProvider provider; private String providerId; // Getters and Setters (Omitted for brevity) }

The User class contains information about the authentication provider. Following is the definition of the AuthProvider enum -

package com.example.springsocial.model; public enum AuthProvider { local, facebook, google, github }

Creating the repositories for accessing data from the database

Let’s create the repository layer for accessing data from the database. The following UserRepository interface provides database functionalities for the User entity. Thanks to Spring-Data-JPA, we don’t need to write much code here -

package com.example.springsocial.repository; import com.example.springsocial.model.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); Boolean existsByEmail(String email); }

What’s next?

In this article, we configured our application and defined the entity classes and repositories. In the next article, we’ll learn how to perform social as well as email/password based login using Spring Security.

Read Next: Spring Boot OAuth2 Social Login with Google, Facebook, and Github - Part 2