Basic authentication : Vanilla JS

Ever thought of how websites and web server protect their secret behind the door well it's not much different than the real world

  1. You buy a security system
  2. You lock your stuff behind the security system

Easy right? Just like there are different types of security system available for real world we have different type of systems for the web too
Some of the popular ones are :

  • Basic Authentication
  • Bearer/Token Authentication
  • OAuth Authentication

Basic Authentication is the oldest of the authentication available it's not much popular now
But before understanding more advanced authentications it's absolute neccesarry

so fire up your node and let's understand the authentication process

Create a folder Tutorial
In here all of our backend code will lie
mkdir Tutorial
initialize the npm using npm init command

once initialized install express from npm and add to the dependency list
npm install express --save

once express is installed make a app.js file in the root directory and load the express module

const express = require("express")
const app = express()

process.env.PORT = 3000

app.get("/" , (req ,res)=>{
    res.status(200).send({"STATUS":"SUCCESS"})
})

app.listen(3000 , ()=>{
    console.log(`STARTED LISTENING ON PORT ${process.env.PORT}`)
});

we also created our first route the root route

run your node server by
node app.js

let's lock out root route behind a middle ware function which will first authenticate the user with the secret

const isAuthenticated = (req , res , next)=>{
    next()
}

app.get("/" ,isAuthenticated, (req ,res)=>{
    res.status(200).send({"STATUS":"SUCCESS"})
})

and then modifying the middle ware function to check the user provided credential against the credential stored on the server

const credentials = {secretName:"Anas Aijaz" , secretPassword:"Catsaresosus"}

const isAuthenticated = (req , res , next)=>{
    const [name , password] = ["Anas Aijaz" , "Dogsaresosus"]

    // We will add code here later

    if(name===credentials.secretName && password===credentials.secretPassword){
        // The User is authenticated
        return next()
    }

    // User is not authenticated give a reponse 401
    res.set('WWW-Authenticate', 'Basic realm="Access to Index"')
    res.status(401).send("Unauthorised access")


}

notice how we delibrately provided a wrong password
let's see what response we get in browser

Oops you the content is locked now and needs a right secret to open

let's work our way through the front end to take input from the user and send it to the server

create a folder beside the Tutorial folder named client and add a index.html index.js in it

cd ../ && mkdir client && cd client && touch index.html index.js

now create a basic form in the html to take input from the user
and on the pressing of the submit button we will use the fetch API to post the data to the server

<form>
            <label>username</label>
            <input name="username" type="text"/>


            <label>password</label>
            <input type="password" name="password"/>

            <input type="submit"/>
        </form>

and the javascript to prevent reloading of the page and execute a fetch request from behind

document.addEventListener("submit" , (event)=>{
                  event.preventDefault()
               })

ok take the input from the user and store it in the variable username and password

now let's focus on creating a fetch request to our server this fetch request will lie inside the submit event listener

fetch("http://localhost:3000/" , {})
               .then(()=>{})
               .catch(()=>{
                   console.log("an error occured")
               })

the skeleton of fetch request will looks like this

the object passed besides the URI will be the header of our HTTP request

the Header fields of any http request exists in pairs
KEY:VALUE
for example one of the most basic header will be
"Accept: application/json" this will indicate the server that the client will only accept json as a response

just like we can add a "Authorization" key the value of which will be the type of authentication and our email and password separated by a colon ":" encoded in a base64 format so it can be transmitted over the web

"Authorizaton: Basic "

The Headers interface of the fetch api can be conviently used to place these headers in our request

const headers = new Headers()
 headers.append("Accept" , "application/json")

next task is to encode our username:password string into a base64 string we can use the a method of the root window element

const base64data = window.btoa(${username}:${password})

now it's time to append this to our header with the Basic keyword

const auth = Basic ${base64data}

now our fetch requests look like

fetch("http://localhost:3000/", { headers:headers })
      .then(()=>{})
      .catch(()=>{
         console.log("an error occured")
      })
})

this will send a request to our server with the proper credentials

now on the server side we have to get the request and parse the username and password separately

let's do it in your app.js

in the middle ware function we have to first get the authorization headers and then base64 decode the credential after splitting the BASIC part

const encodedAuth = (req.headers.authorization || '')
    .split(' ')[1] || '' // getting the part after Basic

 const [name, password] = Buffer.from(encodedAuth, 'base64')
    .toString().split(':')

after splitting the Basic and base64 part we decoded the string and the again splitting it at ":" (remember we added username:password)

as node don't have the window object we have to use the Buffer.from function to decode the string

finally match the input you got from the request with the server secret

if(name===credentials.secretName && password===credentials.secretPassword){
        // The User is authenticated

        return next()
    }

modify your fetch method to write the document when the request is finally successful

.then((response)=>{
                   console.log(response)
                   if(response.status == 200){
                       document.write("SUCCESFULL LOGIN")
                   }
               })

let's try out our app in the browser

I have provided the inputs with correct secrets let's submit the form

Hurray!!!! We are now authenticated by the server and now can access the restricted area

:PS
There are some caveats in our application such as splitting the >string using ":" delimiter will cause unexpected reaction if the >password or username too have a colon you can fix this by >extracting the username and password by REGEX

you can improve this application by issuing a bearer token and >storing it in cookie to access across pages and maintain the >login state but that's the story of another day :)

further reading

14