Posts Facebook Sign In with ASP.NET Core Web API
Post
Cancel

Facebook Sign In with ASP.NET Core Web API

Similar to my previous post Google Sign In with ASP.NET Core Web API, now with Facebook. The complete project is hosted on https://github.com/veglos/dotnet-facebook-signin-api.

Diagram

/diagram-of-facebook-sign-in diagram of facebook sign in

Pre-Requirements

We must create an App in Facebook for Developers and get the App ID and App Secret generated by Facebook. We will use them later for token validation.

Front-end

First we set up the Facebook login button with the Plugin Configurator. Once the button handles the Facebook SignIn process, we take care of the rest of the flow as indicated in Manually Build a Login Flow.

Bear in mind:

  • Set the correct appId in the first script.
  • Set the data-onlogin in the fb-login-button.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <div id="fb-root"></div>
    <script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v10.0&appId=1234567890&autoLogAppEvents=1" nonce="WSrc5Zps"></script>
    <div class="fb-login-button" data-width="" data-size="large" data-button-type="login_with" data-layout="default" data-auto-logout-link="false" data-use-continue-as="false" data-onlogin="onSignIn"></div>
    <button onclick="signOut()">Sign Out</button>

    <script>
        function onSignIn(response) {

            console.log(response);

            fetch('https://localhost:5001/api/Access/signin-facebook', {
                method: 'POST',
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(response.authResponse)
            })
                .then(response => response.json())
                .then(data => console.log(data))
                .catch(error => console.error('Unable to proccess the request', error));
        }

        function signOut() {

            FB.getLoginStatus(function (response) {
                console.log(response);
              
                FB.logout(function () {

                    fetch('https://localhost:5001/api/Access/signout-facebook', {
                        method: 'POST',
                        headers: {
                            'Accept': 'application/json',
                            'Content-Type': 'application/json'
                        },
                        body: null
                    })
                        .then(response => response.json())
                        .then(data => console.log(data))
                        .catch(error => console.error('Unable to proccess the request', error));

                });
            });
        }
    </script>

</body>
</html>

Back-end

Once we get the token we must verify it

Bear in mind:

  • Set the _settings.Value.FacebookSettings.AppID from appsettings.json
  • Set the _settings.Value.FacebookSettings.AppSecret from a secret manager.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using FacebookSignInApi.Models.Facebook.Requests;
using FacebookSignInApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;

namespace FacebookSignInApi.Controllers
{
    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class AccessController : ControllerBase
    {
        private IFacebookService _facebookService;
        private readonly IOptions<AppSettings> _settings;

        public AccessController(
            IOptions<AppSettings> settings,
            IFacebookService facebookService)
        {
            _settings = settings;
            _facebookService = facebookService;
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("signin-facebook")]
        public async Task<string> SignInFacebook(FacebookSignInRequest request)
        {
            try
            {
                var inputToken = request.AccessToken;
                var accessToken = $"{_settings.Value.FacebookSettings.AppID}|{_settings.Value.FacebookSettings.AppSecret}";
                var result = await _facebookService.DebugToken(inputToken, accessToken);

                // Now we are sure the token is valid for our app, however we must verify if the user from the request is the same as the user within the token.
                if (result.data.is_valid == true && result.data.user_id == request.UserID)
                {
                    // We should now fetch the user's claims and provide her/him with an Access Token.
                    return "OK";
                }
                else
                    throw new Exception("Token is not valid");
            }
            catch (Exception ex)
            {
                return $"ERROR: {ex.Message}";
            }
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("signout-facebook")]
        public async Task<string> SignOutFacebook() //should actually receive a request with the access token and the user Id.
        {
            try
            {
                // Proceed to take any actions if needed such as disabling or deleting the user's refresh token.
                return "OK";
            }
            catch (Exception ex)
            {
                return $"ERROR: {ex.Message}";
            }
}
    }
}

This post is licensed under CC BY 4.0 by the author.