Camkode
Camkode

Basic JWT (JSON Web Tokens) with Node.js and TypeScript

Posted by Kosal

Basic JWT (JSON Web Tokens) with Node.js and TypeScript

JSON Web Tokens (JWTs) are a way to securely transmit information between parties as a JSON object. In TypeScript, you can work with JWTs by using libraries like jsonwebtoken for generating, signing, and verifying tokens.

Below are the steps to work with jsonwebtoken using TypeScript:

Step 1: Install Required Packages

Install Express and jsonwebtoken:

npm install express jsonwebtoken

Step 2: Set Up Dependencies and Initialize Express Server

import express, { Request, Response } from 'express'
import jwt from 'jsonwebtoken'

const app = express()
const PORT = 3000

app.use(express.json())

This step imports necessary modules (express for server creation, jsonwebtoken for token handling), initializes the Express app, and sets the server port to 3000. It also enables the app to parse JSON requests.

Step 3: Define JWT Secret Key and Simulated User Data

const JWT_SECRET = 'your_jwt_secret'

const users = [
  {
    id: 1,
    username: 'user1',
    password: 'password1',
  },
  {
    id: 2,
    username: 'user2',
    password: 'password2',
  },
]

This step establishes a secret key for signing JWT tokens and defines a simulated array of user objects with IDs, usernames, and passwords.

Step 4: Create Function to Generate JWT Tokens

const generateToken = (userId: number): string => {
  return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '1h' }) // Token expires in 1 hour
}

This function generateToken accepts a userId and generates a JWT token using the jsonwebtoken package. It signs the token with the secret key and sets it to expire in 1 hour.

Step 5: Create Login Route to Generate JWT Token

app.post('/login', (req: Request, res: Response) => {
  const { username, password } = req.body

  const user = users.find((u) => u.username === username && u.password === password)

  if (!user) {
    return res.status(401).json({ message: 'Invalid credentials' })
  }

  const token = generateToken(user.id)
  res.json({ token })
})

This route /login listens for POST requests. It receives username and password in the request body, checks if the provided credentials match any user in the simulated users array, and generates a JWT token if the credentials are valid.

Step 6: Create Protected Route Requiring a Valid JWT Token

app.get('/protected', (req: Request, res: Response) => {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    return res.status(401).json({ message: 'Unauthorized: No token provided' })
  }

  jwt.verify(token, JWT_SECRET, (err, decoded) => {
    if (err) {
      return res.status(401).json({ message: 'Unauthorized: Invalid token' })
    }

    res.json({ message: 'Welcome to the protected route' })
  })
})

This route /protected listens for GET requests. It expects a valid JWT token in the Authorization header. It verifies the token's authenticity using jwt.verify with the secret key. If the token is valid, it responds with a welcome message; otherwise, it returns an unauthorized error.

Step 7: Start the Express Server

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

This code starts the Express server, listening on port 3000, and logs a message confirming the server's start.

Full code example

import express, { Request, Response } from 'express'
import jwt from 'jsonwebtoken'

const app = express()
const PORT = 3000

app.use(express.json())

// Secret key for signing the JWT tokens
const JWT_SECRET = 'your_jwt_secret'

// Simulated user data (This might be fetched from a database)
const users = [
  {
    id: 1,
    username: 'user1',
    password: 'password1',
  },
  {
    id: 2,
    username: 'user2',
    password: 'password2',
  },
]

// Generate JWT token
const generateToken = (userId: number): string => {
  return jwt.sign({ userId }, JWT_SECRET, { expiresIn: '1h' }) // Token expires in 1 hour
}

// Simulated login route to generate and return a JWT token
app.post('/login', (req: Request, res: Response) => {
  const { username, password } = req.body

  // Check if user exists and credentials match (This might involve DB queries in a real app)
  const user = users.find((u) => u.username === username && u.password === password)

  if (!user) {
    return res.status(401).json({ message: 'Invalid credentials' })
  }

  const token = generateToken(user.id)
  res.json({ token })
})

// Protected route that requires a valid JWT token
app.get('/protected', (req: Request, res: Response) => {
  const token = req.headers.authorization?.split(' ')[1] // Get token from Authorization header

  if (!token) {
    return res.status(401).json({ message: 'Unauthorized: No token provided' })
  }

  jwt.verify(token, JWT_SECRET, (err, decoded) => {
    if (err) {
      return res.status(401).json({ message: 'Unauthorized: Invalid token' })
    }

    // Token is valid, you can perform actions for the authenticated user here
    res.json({ message: 'Welcome to the protected route' })
  })
})

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

Test the Endpoints

  • Login Endpoint: Send a POST request to /login with the username and password in the request body. You will receive a JWT token in the response.

  • Protected Endpoint: Access the protected route /protected by sending a GET request with the received JWT token in the Authorization header. Ensure you set the Authorization header as Bearer <your_token>. ess the protected route /protected by sending a GET request with the received JWT token in the Authorization header. Ensure you set the Authorization header as Bearer <your_token>.