React Serverless Authentication System: Part 1- Netlify Function
By: Mir Sahib
Tags: Serverless, Reactjs, Authentication, AWS Lambda, Netlify

Introduction

In this two part tutorial series we are going to learn how to create a serverless authentication system using netlify function.Netlify functions are kind of wrapper for AWS lambda funtion which run without needing an AWS account.

Prerequisite:

Node version: 10+ npm version: 6+ Github and Netlify account (optional)

Getting started

Before we began let build a react app using the following

command

npx create-react-app serverless-authentication

Or you can clone this repo https://github.com/netlify/create-react-app-lambda and run npm install && netlify dev

Package installation

After creating the react app install the following dependencies

npm i bcryptjs cookie jsonwebtoken mongodb react-router-dom

bcryptjs : lets you hash your passwords which means it convert your password to a random string

: lets you hash your passwords which means it convert your password to a random string cookie : It is a npm module for getting and setting HTTP(S) cookies.

: It is a npm module for getting and setting HTTP(S) cookies. jsonwebtoken : It is a npm module which genereate and verify user authentication token.

: It is a npm module which genereate and verify user authentication token. mongodb: It is a native driver for interacting with a mongodb instance

Install netlify-cli to build and run the netlify function locally

npm install netlify-cli -g

You need to install these module even if you clone the above repo

Initializing the build and folder structure

After installing the dependencies create

netlify.toml file inside the root directory

file inside the directory and lambda,helpers,provider and component folders inside the /src directory.

Your folder structure should look like this

|-- node_modules

| — package.json

| — package-lock.json

| — public

| — README.md

| — src

| | — App.css

| | — App.js

| | — App.test.js

| | — components <---newly created folder

| | — helpers <---newly created folder

| | — index.css

| | — index.js

| | — lambda <---newly created folder

| | — logo.svg

| | — providers <---newly created folder

| | — reportWebVitals.js

| ` — setupTests.js

` — netlify.toml <---newly created file

` — .gitignore

` — .env

paste the following code inside the netlify.toml file,this will allow netlify to look for our serverless function

[build]

functions = "built-lambda"

paste the following code inside the scripts tag of package.json file,this will allow your react app and serverless api’s(i.e netlify function) to be build simultaneously.

"build": "run-p build:**",

"build:app": "react-scripts build",

"build:lambda": "netlify-lambda build src/lambda",

Lets Code

Database Setup

Before we began to create the serverless api’s lets connect our react app with the database.Here i am using mongodb atlas which is a cloud database service used in all kind of web and mobile application.

Create a free cluster and named the database as test with a collection name as users.

with a collection name as Here is the link if you don’t know how to create a mongodb atlas account.

Remember to use 0.0.0.0/0 ip address while setting your network access in mongodb atlas.

Create a new file called db-helper.js inside the src/helpers folder and paste the following code

You need to configure the .env file to use the local environment variable

Explanation: Here we imported the mongodb package and instantiate a mongodb client.The client will connect with our database using the given url and retrieving the data from our users collection.Finally we are returning the client object which will be used by our api’s.

JWT Setup

JWT authentication workflow

We are using JWT token based authentication which mean the server will generate and provide a token to the client using the cookie header.When a client ask to access the restricted part of the site it will send the cookie to the server which then get verified by the server and based on that verification a client will be allowed to access the restricted part.(If you are interested to know more about JWT token please check this link).Furtermore we are passing the JWT token using the cookie header(http only) and this is because it will restrict the client to access the token directly from the browser and it will be immune to XSS attack but storing token inside the cookie header is not the final answer.There is a debate going on in the developshpere on this topic you may check it out from here.

Don’t worry if i say server a lot,you will get the idea of serverless when we finished the project

Create a new file called jwt-helper.js inside the src/helpers folder and paste the following code

Explanation: Here we have imported the jsonwebtoken and cookie module.Inside the createJwtCookie function we are creating a jwt token using userID (mongodb atlas object id)and email address which are passed as the parameter of the funtion,we are also using JWT_Token secret from our environment variable (you can genereate a strong secret password from here)then we serialize the cookie with the given value pair (it just assigning a variable with another one eg: httponly=true).Finally we are returning this cookie object.

clearCookie function will be used when the user is logout from our system.

Building the serverless api’s

Create a new file called signup.js inside the src/lambda folder and paste the following code

Explanation: Here we have imported the bcryptjs module and the helper methodes from the src/helpers folder.Inside the handler function we have create a database client instance which will be used to called the user collection from the database.We extract the email and password from the event.body(basicaly it store the json object which is passed when client make a post request).We then generate a salt to hash our password and stored our hashed password into the database.Finally in the return statement we are sending a json object which content the userID(mongodb object id) and the email address with a header cookie(here sending header cookie is totally optional)

Create a new file called login.js inside the src/lambda folder and paste the following code

Explanation: Here the code is kind of similar with the signup.js page.Initially we are importing the module bcryptjs and the helper methods from the src/helpers folder.We have created a mongodb client instance to get the collection from the database.Then we try to find the user object using the email address provided by the client(which is send with the post request).Later we compare the user password(i.e stored in database) with the provided client password(which is send with the post request).Finally if the password matches we create a jwt token and return a json object (userID and email) by setting the token as header cookie.The rest of the code represent the error handling and closing the db client instance.

Create a new file called logout.js inside the src/lambda folder and paste the following code

Explanation: Here we clear the header cookie and send a json object when the client made get request to this api.

Create a new file called auth.js inside the src/lambda folder and paste the following code

Explanation: Here we have imported the jsonwebtoken and cookie module.Inside the handler function first we extract the cookie from the request header then we check if the cookie or jwt token is present in the header.Next we verify the jwt token using the token secret and the jwt token which is received via cookie.Based on that verification the client will be allowed to visit the restricted page.So finally we send a json object which contain a message that say user auth is true ({auth:true}).The rest of the code represent the error handling.

Create a new file called user.js inside the src/lambda folder and paste the following code.

Explanation: Here the logic behind the code is similar with the /auth api’s .The main difference is in the json object send upon request.Here we are sending the user information(userID,email) as payload.Why we are using this?? this is because in you site you may want to add some information(eg:bio,or for e-commerce site product number which were bought by the user) to user table (mongodb database)

Testing the api’s : I am using postman (you can use any api development tools of your choice).paste the following url in you postman app to test the api’s endpoint.

https://localhost:8888/.netlify/functions/signup

https://localhost:8888/.netlify/functions/login

https://localhost:8888/.netlify/functions/logout

https://localhost:8888/.netlify/functions/user

https://localhost:8888/.netlify/functions/auth

Special Thanks

This tutorial series is heavily influence from Mathias Søholm article on Serverless Authentication in dev.to.You can visit his dev account from here or you can read his article from here.

Conclusion

In the first part of this tutorial series we build a simple serverless authentication api using netlify function.We also use JWT token inside the header cookie to make our app stateless and immune to XSS attack.Passing token inside the cookie is not a bulletproof idea that’s why i would prefer to use firebase or any Outh2 service(google or facebook).