15
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
- You buy a security system
- 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 REGEXyou 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
15