4.4.3.1. Social Login in REST API

The mechanism of social login can be used in REST API too. The complete sample application is available on GitHub and described in the Social Login section, below are the key points of getting an access token with a Facebook account.

  1. Create the restapi package under the root package of web module and implement the custom Spring MVC controller in it. This controller should contain two main methods: get() to get a ResponseEntity instance and login() to obtain an OAuth token.

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity get() {
        String loginUrl = getAsPrivilegedUser(() ->
                facebookService.getLoginUrl(getAppUrl(), OAuth2ResponseType.CODE_TOKEN)
        );
    
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.LOCATION, loginUrl);
        return new ResponseEntity<>(headers, HttpStatus.FOUND);
    }

    Here we check the Facebook code, obtain an access code and issue the access token using OAuthTokenIssuer:

    @RequestMapping(method = RequestMethod.POST, value = "login")
    public ResponseEntity<OAuth2AccessToken> login(@RequestParam("code") String code) {
        User user = getAsPrivilegedUser(() -> {
            FacebookUserData userData = facebookService.getUserData(getAppUrl(), code);
    
            return socialRegistrationService.findOrRegisterUser(
                userData.getId(), userData.getEmail(), userData.getName());
        });
    
        OAuth2AccessTokenResult tokenResult = oAuthTokenIssuer.issueToken(user.getLogin(),
                messageTools.getDefaultLocale(), Collections.emptyMap());
    
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CACHE_CONTROL, "no-store");
        headers.set(HttpHeaders.PRAGMA, "no-cache");
        return new ResponseEntity<>(tokenResult.getAccessToken(), headers, HttpStatus.OK);
    }
  2. Exclude the restapi package from scanning in web/core modules: the OAuthTokenIssuer bean is available only in REST API context, and scanning for it in the application context will cause an error.

    <context:component-scan base-package="com.company.demo">
        <context:exclude-filter type="regex" expression="com\.company\.demo\.restapi\..*"/>
    </context:component-scan>
  3. Create the facebook-login-demo.html file in the modules/web/web/VAADIN folder of your project. It will contain the JavaScript code running on HTML page:

    <html>
    <head>
        <title>Facebook login demo with REST-API</title>
        <script src="jquery-3.2.1.min.js"></script>
        <style type="text/css">
     #users { display: none; }
        </style>
    </head>
    <body>
    <h1>Facebook login demo with REST-API</h1>
    
    <script type="application/javascript"...>
    </script>
    
    <a id="fbLink" href="/app/rest/facebook">Login with Facebook</a>
    
    <div id="users">
        You are logged in!
    
        <h1>Users</h1>
    
        <div id="usersList">
        </div>
    </div>
    
    </body>
    </html>

    The following script will try to login with Facebook. Firstly, it will remove code parameters from URL, then it will pass the code to REST API to get an OAuth access token, and in case of successful authentication we will be able to load and save data as usual.

    var oauth2Token = null;
    
    function tryToLoginWithFacebook() {
        var urlHash = window.location.hash;
    
        if (urlHash && urlHash.indexOf('&code=') >= 0) {
            console.log("Try to login to CUBA REST-API!");
    
            var urlCode = urlHash.substring(urlHash.indexOf('&code=') + '&code='.length);
            console.log("Facebook code: " + urlCode);
    
            history.pushState("", document.title, window.location.pathname);
    
            $.post({
                url: '/app/rest/facebook/login',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                dataType: 'json',
                data: {code: urlCode},
                success: function (data) {
                    oauth2Token = data.access_token;
    
                    loadUsers();
                }
            })
        }
    }
    
    function loadUsers() {
        $.get({
            url: '/app/rest/v2/entities/sec$User?view=_local',
            headers: {
                'Authorization': 'Bearer ' + oauth2Token,
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            success: function (data) {
                $('#fbLink').hide();
                $('#users').show();
    
                $.each(data, function (i, user) {
                    $('#usersList').append("<li>" + user.name + " (" + user.email + ")</li>");
                });
            }
        });
    }
    
    tryToLoginWithFacebook();

    Another example or running a JavaScript code from CUBA applications you can find in the JavaScript Usage Example section.