Spring Security Using Facebook Authorization: A Comprehensive Guide
Tags: webdev, javascript, programming, java
Published: 2024-05-22 09:17:58


In today's digital landscape, integrating third-party login mechanisms into applications has become a standard practice. It enhances user experience by allowing users to log in with their existing social media accounts. In this blog post, we will walk through the process of integrating Facebook authorization into a Spring Boot application using Spring Security.

## Table of Contents
1. Introduction
2. Prerequisites
3. Setting Up Facebook Developer Account
4. Creating a Spring Boot Application
5. Configuring Spring Security for OAuth2 Login
6. Handling Facebook User Data
7. Testing the Integration
8. Conclusion

## 1. Introduction
OAuth2 is an open standard for access delegation, commonly used for token-based authentication. Facebook, among other social media platforms, supports OAuth2, making it possible to integrate Facebook login into your Spring Boot application.

## 2. Prerequisites
Before we start, ensure you have the following:
- JDK 11 or later
- Maven
- An IDE (e.g., IntelliJ IDEA or Eclipse)
- A Facebook Developer account

## 3. Setting Up Facebook Developer Account
To use Facebook login, you need to create an app on the Facebook Developer portal:

1. Go to the [Facebook Developer](https://developers.facebook.com/) website and log in.
2. Click on "My Apps" and then "Create App."
3. Choose an app type (e.g., "For Everything Else") and provide the required details.
4. Once the app is created, go to "Settings" > "Basic" and note down the `App ID` and `App Secret`.
5. Add a product, select "Facebook Login," and configure the Valid OAuth Redirect URIs to `http://localhost:8080/login/oauth2/code/facebook`.

## 4. Creating a Spring Boot Application
Create a new Spring Boot project with the necessary dependencies. You can use Spring Initializr or add the dependencies manually to your `pom.xml`.

### Dependencies
```xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
</dependencies>
```

## 5. Configuring Spring Security for OAuth2 Login
Next, configure Spring Security to use Facebook for OAuth2 login.

### `application.properties`
Add your Facebook app credentials to `src/main/resources/application.properties`.

```properties
spring.security.oauth2.client.registration.facebook.client-id=YOUR_FACEBOOK_APP_ID
spring.security.oauth2.client.registration.facebook.client-secret=YOUR_FACEBOOK_APP_SECRET
spring.security.oauth2.client.registration.facebook.redirect-uri-template={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.facebook.scope=email,public_profile
spring.security.oauth2.client.registration.facebook.client-name=Facebook
spring.security.oauth2.client.registration.facebook.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.facebook.authorization-uri=https://www.facebook.com/v11.0/dialog/oauth
spring.security.oauth2.client.provider.facebook.token-uri=https://graph.facebook.com/v11.0/oauth/access_token
spring.security.oauth2.client.provider.facebook.user-info-uri=https://graph.facebook.com/me?fields=id,name,email
spring.security.oauth2.client.provider.facebook.user-name-attribute=id
```

### Security Configuration
Create a security configuration class to handle the OAuth2 login.

```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorizeRequests ->
                authorizeRequests
                    .antMatchers("/", "/error", "/webjars/**").permitAll()
                    .anyRequest().authenticated()
            )
            .oauth2Login(oauth2Login ->
                oauth2Login
                    .loginPage("/login")
                    .userInfoEndpoint(userInfoEndpoint ->
                        userInfoEndpoint
                            .oidcUserService(this.oidcUserService())
                            .userService(this.oAuth2UserService())
                    )
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler())
            );
    }

    private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
        final OidcUserService delegate = new OidcUserService();
        return (userRequest) -> {
            OidcUser oidcUser = delegate.loadUser(userRequest);

            // Custom logic here

            return oidcUser;
        };
    }

    private OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService() {
        final DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
        return (userRequest) -> {
            OAuth2User oAuth2User = delegate.loadUser(userRequest);

            // Custom logic here

            return oAuth2User;
        };
    }
}
```

## 6. Handling Facebook User Data
After a successful login, you might want to handle and display user data.

### Custom User Service
Create a custom service to process user details.

```java
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Set;
import java.util.HashMap;

@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {

    private final DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) {
        OAuth2User oAuth2User = delegate.loadUser(userRequest);

        Map<String, Object> attributes = new HashMap<>(oAuth2User.getAttributes());
        // Additional processing of attributes if needed

        return oAuth2User;
    }
}
```

### Controller
Create a controller to handle login and display user info.

```java
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LoginController {

    @GetMapping("/login")
    public String getLoginPage() {
        return "login";
    }

    @GetMapping("/")
    public String getIndexPage(Model model, @AuthenticationPrincipal OAuth2User principal) {
        if (principal != null) {
            model.addAttribute("name", principal.getAttribute("name"));
        }
        return "index";
    }
}
```

### Thymeleaf Templates
Create Thymeleaf templates for login and index pages.

#### `src/main/resources/templates/login.html`
```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <a href="/oauth2/authorization/facebook">Login with Facebook</a>
</body>
</html>
```

#### `src/main/resources/templates/index.html`
```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Home</title>
</head>
<body>
    <h1>Home</h1>
    <div th:if="${name}">
        <p>Welcome, <span th:text="${name}">User</span>!</p>
    </div>
    <div th:if="${!name}">
        <p>Please <a href="/login">log in</a>.</p>
    </div>
</body>
</html>
```

## 7. Testing the Integration
Run your Spring Boot application and navigate to `http://localhost:8080`. Click on the "Login with Facebook" link and authenticate with your Facebook credentials. If everything is set up correctly, you should be redirected to the home page with your Facebook profile name displayed.


Integrating Facebook login into your Spring Boot application using Spring Security enhances user experience and leverages the power of OAuth2. With this setup, users can easily log in with their existing Facebook accounts, providing a seamless and secure authentication process.

By following this guide,