2
votes

I followed the steps in the ASP.NET Core documentation to add Facebook/Google login to my application:

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/

It works perfect as it is.

The problem is I would like to have an Ionic 2 client application (using Angular 2) and an ASP.NET Core API as the backend.

In the docs, after we configure the social media middlewares, their login buttons magically show in the MVC application.

Since ASP.NET Core MVC applications and WebAPIs are essentially the same thing, I think I could use this example, just changing the frontend.

I read a lot about authentication, Identity Server 4, JWT, OpenID, etc, but it is a very broad subject and I'm getting lost on what to focus on research...

So far, from what I understood, I will need the Ionic application to authenticate with the social provider. This will generate a token, that I should pass to the API, who will then validate this token with the social provider to grant access to its contents. Is this flow correct? How could I validate the received token in the API?

1
Are you able to find any solution?Naveed Ahmed
@NaveedAhmed Yes I did, but not using facebook directly. I solved using Firebase authentication, which also supports Facebook and other social mediarbasniak
Are you using any plugin fro Firebase authentication for ionic 2?Naveed Ahmed
@naveedahmed When I'm back to the office on Tuesday I'll post an answer with the detailsrbasniak
@NaveedAhmed And you're welcome...rbasniak

1 Answers

2
votes

Here's the solution I used:

1) There are 2 authentication levels - Ionic app - API

2) When the user logs in the app I use Firebase authentication, which returns a token to me if everything is ok. At this point the user is authenticated on the app and I save the token for the call to the API.

3) When the user needs access to any resource, there will be a call to the API. This call will need some sort of authentication too, because the API is not public.

4) I get the token I saved on (2) and I put it in the header of my http request:

let headers = new Headers();

headers.append('Content-Type', 'application/json');
headers.append('Authentication', `${my-saved-token}`);

let options = new RequestOptions({ headers: headers });

return this.http.get(url, options)
            .toPromise()
            .then( .... )

5) On server side (I'm using ASP.NET Core), I created a custom middleware which reads the header of every request and looks for the 'Authentication' key. If it's not there, it just return 401 error, otherwise it validates the token, and if it's valid, it sends the request to the next middleware in the pipeline. The validation service is not shown here, but I used the code on this answer: Firebase authentication asp.net core

public class AuthenticationValidatorMiddleware
{
    private readonly RequestDelegate _next;

    private ITokenValidation TokenValidator { get; set; }

    public AuthenticationValidatorMiddleware(RequestDelegate next, ITokenValidation tokenValidator)
    {
        _next = next;

        TokenValidator = tokenValidator;
    }

    public async Task Invoke(HttpContext context)
    {
        if (!context.Request.Headers.Keys.Contains("Authentication"))
        {
            context.Response.StatusCode = 400; //Bad Request     

            await context.Response.WriteAsync("Authentication is missing");

            return;
        }
        else
        {
            var token = context.Request.Headers["authentication"];

            if (!TokenValidator.Validate(token))
            {
                context.Response.StatusCode = 401; //UnAuthorized

                await context.Response.WriteAsync("Invalid authentication");

                return;
            }
        }
        await _next.Invoke(context);
    }
}

On client app I used AngularFire2 to do the authentication, but bear in mind that when using Firebase + AngularFire2 there's no support in Ionic 2 for the login methods offered by them.

To solve this you have to use cordova-plugin-inappbrowser and cordova-plugin-facebook4. Then you'll log in the app via Facebook plugin, get the Facebook authentication token and then use this token to log in Firebase. Here's my signin method:

public signInWithFacebook(): firebase.Promise<any>
{
    if (this.platformService.is('cordova'))
    {
        return Facebook.login(['email', 'public_profile']).then(res =>
        {
            const facebookCredential = firebase.auth.FacebookAuthProvider.credential(res.authResponse.accessToken);

            return firebase.auth().signInWithCredential(facebookCredential);
        });
    }
    else
    {
        return this.firebaseAuthenticationService.login(
            {
                provider: AuthProviders.Facebook,
                method: AuthMethods.Popup
            });
    }

}

As you can see in the code above, if I detect that I'm running on browser, I use the native AngularFire2 authentication, if I'm running on a device, then I log in via the Facebook cordova plugin, the the credentials and then pass it to Firebase.

The answer is big but I hope I could made myself clear... if you have any further questions, please ask...