In this lesson, we'll implement a robust authentication system using JSON Web Tokens (JWT) to protect our API routes. We'll create middleware that verifies tokens and ensures only authenticated users can access protected resources.
JWT authentication in APIs typically follows the Bearer Token pattern, which is an industry-standard approach for token-based authentication:
<aside> 🔑
Bearer Token Flow
Authorization
header: Bearer <token>
Advantage | Description |
---|---|
Stateless | No server-side session storage needed |
Scalable | Works across multiple servers without shared state |
Standard | Widely adopted HTTP authentication scheme |
Secure | Token never stored in cookies (no CSRF issues) |
Our authentication system consists of two main components:
src/utils/jwt.ts
src/middleware/auth.ts
First, let's extend our JWT utilities to handle token verification:
<aside> 📝
File: src/utils/jwt.ts
</aside>
import { SignJWT, jwtVerify, decodeJwt } from 'jose'
import { createSecretKey } from 'crypto'
import env from '../env.ts'
export interface JwtPayload {
id: string
email: string
username: string
}
// Existing generateToken function...
export const verifyToken = async (token: string): Promise<JwtPayload> => {
const secretKey = createSecretKey(env.JWT_SECRET, 'utf-8')
const { payload } = await jwtVerify(token, secretKey)
return {
id: [payload.id](<http://payload.id>) as string,
email: [payload.email](<http://payload.email>) as string,
username: payload.username as string,
}
}