React and .NET Core Web API Authentication using Firebase

Authentication is a key part of any web or mobile application that wants to provide a personalized experience to each of the end-users. It is simply a must when developing any modern application, that is why in this article, I will guide you through integrating Firebase Authentication into your React app and securing your .NET Core Web API.

Google Firebase is a BaaS(Back-end as a Service) solution developed by Google, that can be easily integrated into your React application. It provides all of the standard authentication needs out of the box, such as:

  • Register
  • Confirm Email
  • Sign In / Sign Out
  • Forgot Password
  • Reset Password
  • etc..

In addition to all this, there is a simple way to integrate it with your .NET Core Web API and have authorized REST endpoints that can be accessed only with a token that is generated by Firebase.

Prerequisites:

  • Created React app using create-react-app – Read more
  • Created Firebase project
  • Created Web App inside Firebase project
  • Enabled Email/Password provider under the Firebase Console > Authentication > Sign in method

Integrating Firebase into your React project

First thing is first, to install the Firebase SDK, open the terminal and run:

npm  install firebase

This will install the latest version of Firebase to your project.

Next, you want to create a firebase.jsx file and inside it, you should import the Firebase SDK, add your firebase app config, and export the firebase auth service.
It should look something like this:

import firebase from "firebase"

const firebaseConfig = {
  apiKey: "AIzaSyDT-IB1QNlvDOY-NowOKgNkBiTjb8-aF9Q",
  authDomain: "my-app.firebaseapp.com",
  databaseURL: "https:// my-app.firebaseio.com",
  projectId: " my-app ",
  storageBucket: " my-app.appspot.com",
  messagingSenderId: "400223162389",
  appId: "1:700928495989:web:e7d8c9a9c9ba31a1fc",
  measurementId: "G-WHOQE5ZWTQ"
};
const firebaseApp = firebase.initializeApp(firebaseConfig);

export default auth

You can find your firebaseConfig under Firebase Console > Project Settings > *select your app* > Config

IMPORTANT NOTE: Your config file is free to be shown publicly as long as you set up the Authorized Domains properly in Authentication > Sign-In Method in the Firebase Console. This will block any domains that are not on the list and want to use your config. I have seen plenty of production apps that have the config exposed, so this should not be an issue.

User Registration

Now comes the real power of Firebase authentication, using a few simple lines of code you get a full registration functionality out of the box.
This boils down to importing the auth service you just created

import auth from ‘<path to your firebase.jsx file>’

And whenever you want to register a user with email and password, just call:

auth.createUserWithEmailAndPassword(email, password)
     .then((authUser) => { 
          alert("successfully logged in!") })
     .catch((error) => { 
          alert(error.message) });

Congratulations! You just successfully registered to your application!

Next, we want to subscribe to the back end event stream for the user in our App.js root component and keep track of the logged-in user in the application. This can be simply done with one simple UseState and one simple UseEffect:

const [loggedInUser, setLoggedInUser] = useState(null);
  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged(
(authUser) => {
      if (authUser) {
        //user has logged in – add getToken here
        setLoggedInUser(authUser);
      } else {
        //user has logged out
        setLoggedInUser(null);
      }
    });
    return () => {
      unsubscribe()
    }
  }, [loggedInUser]);

Now every time the state of the user is changed on the back end, it will be changed inside the application too! Powerful huh? My point exactly.

Sign in

Just as simple as registering, the sign in is done with a single call through the auth service.

Import the auth service as done in Register, and whenever you want to sign in a user with email and password, call:

auth.signInWithEmailAndPassword(email, password)
         .then((authUser) => {
              alert('Successfully logged in!');
         })
         .catch((error) => { alert(error.message); });

It is as simple as that!

Getting the Id Token

Now that you have fully functional authenticated app, let’s see how can we protect our .NET Core Web API from users that are not registered to our application.

For this, we are going to use the user’s JWT id_token that we can get when the user is logged in.

Take a look at the UseEffect in App.js where the comment ‘getToken here’ is. At that point, we should do

authUser.getIdToken(false)
    .then((token) => { 
         localStorage.setItem(‘id_token’, token) 
    });

This will get the id_token for the user and store it inside local storage, so we can use it every time we want to make an authorized call to out .NET Core Web API

Note: You can decode this token here if you want to see the contents of it! Adding the JWT to the request is as simple as getting the token from local storage and adding the following header to your request.

let token = localStorage.getItem(constants.tokenlskey);
let header = { “Authorization” : “Bearer ” + token }; 

Add this header to the request when calling your .NET Core Web API.

Securing your .NET Core Web API using Firebase

In order to authorize your .NET Core Web API you will need the following NuGet packages:

  • Microsoft.AspNetCore.Authentication
  • Microsoft.AspNetCore.Authentication.Abstractions
  • Microsoft.AspNetCore.Authentication.Core
  • Microsoft.AspNetCore.Authentication.JwtBearer

After installing those, add the following to your startup services configuration:

services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
 {
     var authority = $"https://securetoken.google.com/{FirebaseSettings.AppId}";
     var audience = FirebaseSettings.AppId;

     options.Audience = audience;
     options.Authority = authority;
     options.TokenValidationParameters = new TokenValidationParameters
     {
            ValidateIssuer = true,
            ValidIssuer = authority,
            ValidateAudience = true,
            ValidAudience = audience,
            ValidateLifetime = true
     };
});

You should replace FirebaseSetting.AppId with your Firebase App Id

If you want to read more on JWT bearer validation, you can do here.

Next in your Configure method, you should add:

app.UseAuthentication();

right after app.UseRouting();

Finally, just add the [Authorize] decorator to your controller or actions that you want to authorize using this scheme, and enjoy the comfort of a secured API using just a few lines of code!