I just announced the newSpring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

1. Overview

In this tutorial, we’ll focus on adding a new Facebook login to an existing form-login app.

We’re going to be using the Spring Social support to interact with Facebook and keep things clean and simple.

2. Maven Configuration

First, we will need to add spring-social-facebook dependency to our pom.xml:

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-facebook</artifactId>
</dependency>

3. Security Config – Just Form Login

Let’s first start from the simple security configuration where we just have form-based authentication:

@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = { "org.baeldung.security" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/login*").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/login").permitAll();
    } 
}

We’re not going to spend a lot of time on this config – if you want to understand it better, have a look at the form login article.

4. Security Config – Adding Facebook

Now, let’s add a new way to authenticate into the system – driven by Facebook:

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ConnectionFactoryLocator connectionFactoryLocator;

    @Autowired
    private UsersConnectionRepository usersConnectionRepository;

    @Autowired
    private FacebookConnectionSignup facebookConnectionSignup;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .authorizeRequests()
        .antMatchers("/login*","/signin/**","/signup/**").permitAll()
        ...
    } 

    @Bean
    public ProviderSignInController providerSignInController() {
        ((InMemoryUsersConnectionRepository) usersConnectionRepository)
          .setConnectionSignUp(facebookConnectionSignup);
        
        return new ProviderSignInController(
          connectionFactoryLocator, 
          usersConnectionRepository, 
          new FacebookSignInAdapter());
    }
}

Let’s carefully look at the new config:

  • we’re using a ProviderSignInController to enable the Facebook authentication
  • by sending a POST to “/signin/facebook” – this controller will initiate a user sign-in using the Facebook service provider
  • we’re setting up a SignInAdapter to handle the login logic in our application
  • and we also setting up a ConnectionSignUp to handle signing up users implicitly when they first authenticate with Facebook

5. The Sign-In Adapter

Simply put, this adapter is a bridge between the controller above – driving the Facebook user sign-in flow – and our specific local application:

public class FacebookSignInAdapter implements SignInAdapter {
    @Override
    public String signIn(
      String localUserId, 
      Connection<?> connection, 
      NativeWebRequest request) {
        
        SecurityContextHolder.getContext().setAuthentication(
          new UsernamePasswordAuthenticationToken(
          connection.getDisplayName(), null, 
          Arrays.asList(new SimpleGrantedAuthority("FACEBOOK_USER"))));
        
        return null;
    }
}

Note that users logged-in using Facebook will have role FACEBOOK_USER, while users logged in using form will have role USER.

6. Connection Sign Up

When a user authenticates with Facebook for the first time, they have no existing account in our application.

This is the point where we need to create that account automatically for them; we’re going to be using a ConnectionSignUp to drive that user creation logic:

@Service
public class FacebookConnectionSignup implements ConnectionSignUp {

    @Autowired
    private UserRepository userRepository;

    @Override
    public String execute(Connection<?> connection) {
        User user = new User();
        user.setUsername(connection.getDisplayName());
        user.setPassword(randomAlphabetic(8));
        userRepository.save(user);
        return user.getUsername();
    }
}

As you can see, we created an account for the new user – using their DisplayName as username.

7. The Facebook Properties

Next, let’s configure Facebook properties in our application.properties:

spring.social.facebook.appId=YOUR_APP_ID
spring.social.facebook.appSecret=YOUR_APP_SECRET

Note that:

  • We need to create a Facebook application to obtain appId and appSecret
  • From Facebook application Settings, make sure to Add Platform “Website” and http://localhost:8080/ is the “Site URL”

8. The Front End

Finally, let’s take a look at our front end.

We’re going to now have support for these two authentication flows – form login and Facebook – on our login page:

<html>
<body>
<div th:if="${param.logout}">You have been logged out</div>
<div th:if="${param.error}">There was an error, please try again</div>

<form th:action="@{/login}" method="POST" >
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="submit" value="Login" />
</form>
	
<form action="/signin/facebook" method="POST">
    <input type="hidden" name="scope" value="public_profile" />
    <input type="submit" value="Login using Facebook"/>
</form>
</body>
</html>

Finally – here’s the index.html:

<html>
<body>
<nav>
    <p sec:authentication="name">Username</p>      
    <a th:href="@{/logout}">Logout</a>                     
</nav>

<h1>Welcome, <span sec:authentication="name">Username</span></h1>
<p sec:authentication="authorities">User authorities</p>
</body>
</html>

Note how this index page is displaying usernames and authorities.

And that’s it – we now have two ways to authenticate into the application.

9. Conclusion

In this quick article we learned how to use spring-social-facebook to implement a secondary authentication flow for our application.

And of course, as always, the source code is fully available over on GitHub.

I just announced the new Spring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

newest oldest most voted
Hinotori
Guest
Hinotori

Thanks! Very good article!

Eugen Paraschiv
Guest

Glad you liked it. Cheers,
Eugen.

Brandon Vulaj
Guest
Brandon Vulaj

I’m integrating this into an application using spring session (redis) and csrf – should this configuration work as expected still?

Eugen Paraschiv
Guest

Hey Brandon,
Theoretically – yes. Spring Session shouldn’t have an impact, and CSRF is something you’ll of course need to make sure your front-end handles, but as long as that’s the case – you should be good to go.

That being said, whenever you get part of a working project and move it to another project – there are always things you may need to tweak – as I’m sure you know. So, keep that in mind when you move the logic over.

Cheers and best of luck with the implementation,
Eugen.

Brandon Vulaj
Guest
Brandon Vulaj

@baeldung:disqus – Have you seen the social providers not matching the `state` param? The request goes out with the proper state param, and the request comes back with the proper state param, however, the check in verifyStateParameter always sees originalState on the Session as null. Could this be an integration issue with Spring Session?

Eugen Paraschiv
Guest

Hey @brandonvulaj:disqus – I haven’t seen that exact behavior no – but keep in mind a couple of important notes. First – some of the social providers don’t 100% adhere to the spec. It’s a bit unfortunate but that is sometimes the case. Second – the implementation is not set in stone, and – if a change did occur – the library may need to catch up. So, in cases like this, you’ll need to debug your way through whatever is happening – and of course have a good understanding of what “should” be happening first. Hope that points you… Read more »

Kingsley
Guest
Kingsley

Thanks for this very good article. How can one integrate other social logins like Twitter, Google and Linked into this sample you provided?

Eugen Paraschiv
Guest

Well, at a high level – you need to use the associated Spring Social project – there are solutions for Twitter, Google, etc. There might be some implementation details that vary, but that’s the general direction to go in.

Kingsley
Guest
Kingsley

Thank you so much for your kind response.

Robert Vangor
Guest
Robert Vangor

Great article, you really helped me !
Can I use Spring Social Google community project as well ? Is it outdated or will it work fine even with spring boot ?

Eugen Paraschiv
Guest

Hey Robert, I’m glad the material was helpful. I could add that to the Content Calendar of the site, sure – but it should actually be relatively similar.
Cheers,
Eugen.