SPA - Firebase and .Net WebApi 2 Authentication

I have a one-page application written in AngularJs (it doesn't matter at the moment). The application is hosted on IIS, and it is composed of index.html plus many client assets.

On the backend, I have WebApi 2, also hosted in IIS as a standalone application.

For client authentication, I use Firebase (simple login) with several social networking technologies such as Facebook, Twitter or Google.

So far so good. I like how easy it is to enable twitter authentication, for example with firebase.

Upon entering the social network, I will return from firebase, firebaseAuthToken and the accesstoken provider.

Now I want to use firebaseAuthToken or a vendor access token for authentication using my WebApi.

Question: What is the best way to authenticate using WebApi in these conditions?

There is no way to use only firebase to store my data and get rid of the web api, because I have in place a complex business logic on the server.

One stupid idea that I have so far is to transfer the access token of the social provider to the server, check the token against the provider, and then issue the security token using Owin-Katana.

I do not use the support of social providers from katana because of the lack of documentation, complexity and poor integration with single-page applications. I found a visual studio template for SPA too mvc. But here I am :)

+6
source share
1 answer

tl; dr - Demo project on GitHub

The following steps may seem long, but in fact it is very simple. I created my demo project in just an hour or so.


I agree with you in using Owin and Katana. I already went through this process, and it was not a very good experience. Using Firebase was a lot easier.

All this can be done using JWT!

When you authenticate through Firebase and any social provider, you return the JSON Web Token (JWT) - firebaseAuthToken .

Take Firebase Secret From The Control Panel

How JWT works, we have a secret token and a client token. The client token is the firebaseAuthToken, which we get after logging in. A secret token is generated for us in the Firebase panel.

Firebase JWTs Dashboard

Keep your Firebase secret in the appSettings section of your Web.config

We need to save this secret key in the Web.config file so that it can be accessed later.

 <add key="FirebaseSecret" value="<Firebase-Secret-Token-Goes-Here" /> 

Create an action filter to test JWT from the authorization header

We can verify that the request is valid by passing the client token in the authorization header. On the server we can store our secret key, which we get from our Firebase panel. When the request is validated by the web API, we can decode the JWT using the JWT library ( available from NuGet ). If the decoding is successful, we can check the token so that it does not expire.

 public class DecodeJWT: ActionFilterAttribute { public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { string firebaseAuthToken = string.Empty; if (actionContext.Request.Headers.Authorization != null) { firebaseAuthToken = actionContext.Request.Headers.Authorization.Scheme; } else { throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized"); } string secretKey = WebConfigurationManager.AppSettings["FirebaseSecret"]; try { string jsonPayload = JWT.JsonWebToken.Decode(firebaseAuthToken, secretKey); DecodedToken decodedToken = JsonConvert.DeserializeObject < DecodedToken > (jsonPayload); // TODO: Check expiry of decoded token } catch (JWT.SignatureVerificationException jwtEx) { throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized"); } catch (Exception ex) { throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized"); } base.OnActionExecuting(actionContext); } } 

Create a $ httpInterceptor add a firebaseAuthToken in the header for each request

On the client, the trick is that the token must be transferred every time. To make this easier, we need to create a $httpInterceptor with Angular that checks for the presence of firebaseAuthToken on sessionStorage .

 .factory('authInterceptor', function ($rootScope, $q, $window) { return { request: function (config) { config.headers = config.headers || {}; if ($window.sessionStorage.firebaseAuthToken) { config.headers.Authorization = $window.sessionStorage.firebaseAuthToken; } return config; }, response: function (response) { if (response.status === 401) { // TODO: User is not authed } return response || $q.when(response); } }; }) 

Set firebaseAuthToken to sessionStorage on successful login

Whenever a user logs in, we can set the value of sessionStorage .

 $rootScope.$on('$firebaseSimpleLogin:login', function (e, user) { // add a cookie for the auth token if (user) { $window.sessionStorage.firebaseAuthToken = user.firebaseAuthToken; } cb(e, user); }); 

Register DecodeJWT Filter Globally

Inside the WebApiConfig.cs Register method, we can set the DecodeJWT filter for all of our ApiControllers.

 config.Filters.Add(new DecodeJWT()); 

Now, when we make a request to ApiController, it rejects it if a valid JWT does not exist. Therefore, after a user logs in, we can save our data in ApiController if it does not already exist.

 // globally uses DecodeJWT public class UsersController: ApiController { // POST api/users public void Post([FromBody] FbUser user) // See GitHub for this Model { // Save user if we do not already have it } } 
+10
source

Source: https://habr.com/ru/post/972201/


All Articles