Self-paced

Explore our extensive collection of courses designed to help you master various subjects and skills. Whether you're a beginner or an advanced learner, there's something here for everyone.

Bootcamp

Learn live

Join us for our free workshops, webinars, and other events to learn more about our programs and get started on your journey to becoming a developer.

Upcoming live events

Learning library

For all the self-taught geeks out there, here is our content library with most of the learning materials we have produced throughout the years.

It makes sense to start learning by reading and watching videos about fundamentals and how things work.

Search from all Lessons


LoginGet Started
← Back to Lessons
  • APIs

  • Express

  • HTTP

  • Security

  • Authentication

  • typeOrm

Edit on Github

Understanding JWT and how to implement a simple JWT with Express

JSON Web Tokens (JWT) for API Authentication

JSON Web Tokens (JWT) for API Authentication

In the world of modern web development, user authentication and authorization are crucial aspects of protecting APIs and sensitive data. Among the most popular solutions are JSON Web Tokens (JWT), an open and lightweight standard that defines a compact and self-contained mechanism for secure transmission of information between client and server parties.

What are JWTs?

A JWT is a token that contains information about a user's identity and authorization to access specific resources. It consists of three parts:

☝️ If you don't know what a token is, I would recommend this reading.

Header: Specifies the token type, signing algorithm and other relevant information.

Payload: Contains data about the user, such as identification, name, roles and expiration date of the token.

Signature: Guarantees the integrity and authenticity of the token by means of a digital signature using a cryptographic algorithm and a secret key shared between the server and the client.

How does JWT work in API authentication?

The scheme to be implemented in this case can be summarized as follows

Authentication workflow](https://storage.googleapis.com/breathecode-asset-images/3a5642b10731f82b15ed1d3abc81856cdc0a4a8cf42b6640b70f1ad619c9e7dd.png?raw=true)

  1. Login: The user enters his credentials (email and password) in the client.

  2. Authentication: The server validates the user's credentials and, if correct, generates a JWT with the user's information and signs it with its secret key.

  3. Sending the token: The server sends the JWT to the client in response to the login request.

  4. Storing the token: The client stores the JWT securely, usually in local storage or in an HTTP cookie.

  5. Subsequent requests: In each subsequent API request, the client includes the JWT in the authorization header.

  6. Token validation: The server verifies the signature of the JWT to ensure its authenticity and integrity. If the token is valid, it extracts the user information from the payload and uses it to authorize access to the requested resource.

Implementing JWT in your project API

1) Installation

Install these 3 libraries that will take care of generating the JWT tokens:

1npm install express-jwt @types/express-jwt jsonwebtoken @types/jsonwebtoken --save

2) Login endpoint

Second step is to create one API Route that can be called by the client to generate a token (a.k.a: login), this endpoint will receive the email and password information form the body and look for any user in the DB that matches those two values.

If the value is found, it will generate a token by calling the function jwt.sign.

1//this line goes in your public_routes.ts 2import jwt from 'jsonwebtoken' 3 4router.post('/token', safe(createToken)); 5 6// this function goes in your actions.ts 7export const createToken = async (req: Request, res: Response): Promise<Response> =>{ 8 9 if(!req.body.email) throw new Exception("Please specify an email on your request body", 400) 10 if(!req.body.password) throw new Exception("Please specify a password on your request body", 400) 11 12 const userRepo = await getRepository(Users) 13 14 // We need to validate that a user with this email and password exists in the DB 15 const user = await userRepo.findOne({ where: { email: req.body.email, password: req.body.password }}) 16 if(!user) throw new Exception("Invalid email or password", 401) 17 18 // this is the most important line in this function, it create a JWT token 19 const token = jwt.sign({ user }, process.env.JWT_KEY as string); 20 21 // return the user and the recently created token to the client 22 return res.json({ user, token }); 23}

3) Validating requests with JWT

Now we need to add a middleware that will check for the token on the Request Authoritzation Header. The middleware will intercept each request and execute the next function to proceed only if it succeeds in validating the token, otherwise it will return an error.

Add these two middlewares inside ./src/app.js that will take care of enforcing the token.

1// ⬆ anything ABOVE is public 2import jwt, { Options } from 'express-jwt'; 3 4let opt: Options = { secret: process.env.JWT_KEY as string, algorithms: ["HS256"] } 5app.use(jwt(opt)) 6// ⬇ anything BELOW is public 7app.use(((err: any, req: any, res: any, next: any) => { 8 if (err) console.error(err); 9 if (err.name === 'UnauthorizedError') { 10 return res.status(401).json({ status: err.message }); 11 } 12 next(); 13}))

⚠️ Important

Any endpoint that is added BELOW these middlewares will be private, for example:

1app.get('/public', (req, res) => { 2 res.json({ message: "Anyone can see me" }); 3}) 4 5// ⬆ anything ABOVE is public 6app.use(jwt(opt)) // ⬅ JWT Middleware 7// ⬇ anything BELOW is public 8 9app.get('/private', (req, res) => { 10 res.json({ message: "If you can se me, you are logged in" }); 11})

4) Get the authenticated user

We are done, but if only logged in users are supposed to call our private endpoints, then we need a way to know who is calling them, for example we can use req.user from now on, to identify request user):

1export const getMe = async (req: Request, res: Response): Promise<Response> =>{ 2 3 const users = await getRepository(Users).find({ where: }); 4 // ⬇ not comming from the BD 5 return res.json(req.user); 6}

Or we can use that info and get more information form the requester from the database.

1export const getMe = async (req: Request, res: Response): Promise<Response> =>{ 2 3 4 // ⬇ not comming from the BD 5 return res.json(req.user); 6}

Implementing JWT in your project's front-end

On the front-end side, we need two main steps: Creating a new token (a.k.a: login) and appending the token to the headers when fetching any other private endpoints.

Create new token:

Based on the endpoints we built earlier we have to POST /token with the username and password information in the request body.

1const login = async (username, password) => { 2 const resp = await fetch(`https://your_api.com/token`, { 3 method: "POST", 4 headers: { "Content-Type": "application/json" }, 5 body: JSON.stringify({ username, password }) 6 }) 7 8 if(!resp.ok) throw Error("There was a problem in the login request") 9 10 if(resp.status === 401){ 11 throw("Invalid credentials") 12 } 13 else if(resp.status === 400){ 14 throw ("Invalid email or password format") 15 } 16 const data = await resp.json() 17 // Save your token in the localStorage 18 // Also you should set your user into the store using the setItem function 19 localStorage.setItem("jwt-token", data.token); 20 21 return data 22}

Fetch any private information

Let's suppose I am using the front-end application and I just logged in, but now I want to fetch some private or protected endpoint:

1// Assuming "/protected" is a private endpoint 2const getMyTasks = async () => { 3 // Retrieve token from localStorage 4 const token = localStorage.getItem('jwt-token'); 5 6 const resp = await fetch(`https://your_api.com/protected`, { 7 method: 'GET', 8 headers: { 9 "Content-Type": "application/json", 10 'Authorization': 'Bearer ' + token // ⬅⬅⬅ authorization token 11 } 12 }); 13 14 if(!resp.ok) { 15 throw Error("There was a problem in the login request") 16 } else if(resp.status === 403) { 17 throw Error("Missing or invalid token"); 18 } else { 19 throw Error("Unknown error"); 20 } 21 22 const data = await resp.json(); 23 console.log("This is the data you requested", data); 24 return data 25}

That is it! As you can see, it's very simple to integrate JWT into your application using Express, just four steps on the backend and two steps on the front-ent. For any questions, you can contact me on Twitter @alesanchezr or use the #public-support channel on 4Geeks Academy's Slack community.