The shift from front-end to a bit of back-end
What is it?
JWT stands for Json Web Token and pronounced as “JOT”.
JWT’s are encrypted JSON objects that can’t be altered after their creation and used to establish a secure communication between two parties.
As you can see a token has 3 parts separated by 2 dots:Header
, Payload
and a Signature
Authenticated vs Verification:
- Authentication is performed once in the login method. It’s answering the question of “who are you?”
- Verification re-validates the identity established on login. It’s answering the question of “Are you actually who you say you are?”
In essence, the token will help validate if its the same user that logged in and Here is the flow:
- User makes a request to the
login
endpoint with a valid username and password. - Server generates a token with a
header
,apayload
and asignature
using the secret key. The secret key is stored on the server in a.env
file
- Server’s response to the successful login will also contain the generated token.
- The client will store the token on the client side (Cookie, LocalStorage, SessionStorage)
- User makes a request to another endpoint,
/getImages
(for ex) - The request includes the
Authorization
header. This header contains the token for the server to validate.Authorization : Bearer [tokenStoredOnClientSide]
- Server reads the header, gets access to the client’s token
- Server regenerates the token using the SECRET key in
.env
and compares if
ClientToken === ServerGeneratedTokem
- If they are equal, we are still working with the same user we authenticated in the first place.
Note: I would structure the files differently from what you see, and also use TypeScript. Just wanted to keep it simple :)
Let’s code on the 🅂🄴🅁🅅🄴🅁 side
- Generate a secret key to store inside of
.env
It can be anything really. I just think the following way makes it even harder to decode: Generating a random sequence using the built-in node Crypto library.
require(“crypto”).randomBytes(64).toString(‘hex’)
We specify the length of the bytes to be 64 and convert the base of the string to hex. Your .env
should look like this:
2. Install the JsonWebToken library
npm i jsonwebtoken --save
3. In your index.js
file (the entry to your server) , we will work with the testingJWT
method
4. Generate the token
In the beginning of the tutorial I showed you how the token has three parts.
In the payload part we can store anything we want.
I will store the user’s email. I will be using it later on (check step 8).
Essentially, you can store any set of key pair values.
Note: I created a new file called jwt.js
to separate the token logic from index.js
We call the jwt.sign
method that accepts a payload and a secret key.
Notice how there are 2 dots separate between:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 //header
eyJlbWFpbCI6ImxhcmFtbzE5OTlAZ21haWwuY29tIn0 //payload
QWh4nstEuzbeS3HvBJ8cZg88DHti8vTNtlvRMLDbUJA //signature
4. Assuming you have a login method in your app. You will now call the generateToken
method if login was successful
We are now on the 🄲🄻🄸🄴🄽🅃👤 side
5. The client must store the token on its end.
Assume that the method setItemToStorage(key, item)
exists.
We would call it like this in our login method on the client.
Note:
I am writing this article as I am working on a ReactNative app, hence I am using Encrypted Async Storage to store my token. If you are developing on web, storing it in the Session Storage or Local Storage is fine as well.
6. Let’s say we now make a request to testingJWT
using axios.
- We must get the token we stored.
AssumegetItemFromStorage
already exists.
- We are creating a get request to
testingJWT
. - We are expecting to get back
hello from LaraMo
since this is what we sent back in step 3. - We are passing an
Authorization
header that includes the token in our request. - The server will regenerate the token and will compare if what the client gave it matches.
Back to the 🅂🄴🅁🅅🄴🅁
7. We will create a middleware method that will be invoked before each request that we wish to verify the user. Its purpose is to validate the token.
I added this method inside of jwt.js
8. Now call the middleware, in THE MIDDLE (😊) of your request
Now index.js
should look like this:
- Notice how in step 7 we assigned the payload of the token to
req.userEmail
, this is optional of course, but could be useful as you can store any info about the user in the payload.
Thats all!
Now if I login with the email laramo@gmail.com
and make a request to testingJWT
, if my token is valid I will get:
hello from LaraMo, your email is laramo@gmail.com
If the token is invalid, the server will return forbidden
and status 403
Thanks for reading, and I hope you learn from this as much as I did! :)
Until next time,
LaraMo