Authorization and Authentication in TypeScript: A Complete Guide
In modern web development, application security is a critical aspect. TypeScript, as a superset of JavaScript, provides powerful tools for creating typed and secure authorization and authentication systems. In this article, we will break down key concepts, popular libraries, and write practical examples in TypeScript.
Basic Concepts
Before moving to code, it is important to distinguish between two terms:
- Authentication — verifying user identity (who are you?). Usually done via login/password, tokens, or biometrics.
- Authorization — determining access rights (what are you allowed to do?). For example, access to the admin panel only for the "admin" role.
Popular Libraries for TypeScript
In the TypeScript/Node.js ecosystem, there are several proven solutions:
- Passport.js — the most popular library for authentication strategies (local, JWT, OAuth). It has excellent TypeScript support via
@types/passporttypes. - jsonwebtoken — working with JWT (JSON Web Tokens). Fully typed.
- bcrypt — password hashing. Used together with other libraries.
- express-session — server-side session management.
Example 1: Basic Authentication with JWT
Let's create a simple system with access tokens. Install the dependencies:
npm install express jsonwebtoken bcrypt @types/express @types/jsonwebtoken @types/bcryptLet's create a server with registration and login:
import express, { Request, Response } from 'express';import jwt from 'jsonwebtoken';import bcrypt from 'bcrypt';
const app = express();app.use(express.json());
const SECRET_KEY = 'your-secret-key';const users: { username: string; passwordHash: string }[] = [];
// Registrationapp.post('/register', async (req: Request, res: Response) => { const { username, password } = req.body; const passwordHash = await bcrypt.hash(password, 10); users.push({ username, passwordHash }); res.status(201).json({ message: 'User created' });});
// Loginapp.post('/login', async (req: Request, res: Response) => { const { username, password } = req.body; const user = users.find(u => u.username === username); if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const isValid = await bcrypt.compare(password, user.passwordHash); if (!isValid) return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' }); res.json({ token });});
// Protected routeapp.get('/protected', (req: Request, res: Response) => { const authHeader = req.headers.authorization; if (!authHeader) return res.status(401).json({ error: 'No token provided' });
const token = authHeader.split(' ')[1]; // Bearer token try { const decoded = jwt.verify(token, SECRET_KEY); res.json({ message: 'Access granted', user: decoded }); } catch { res.status(403).json({ error: 'Invalid token' }); }});
app.listen(3000, () => console.log('Server running on port 3000'));Example 2: Middleware for Authorization with Roles
Let's add a role-based model. Create a typed middleware:
interface JwtPayload { username: string; role: 'user' | 'admin';}
// Middleware for authentication checkfunction authenticate(req: Request, res: Response, next: Function) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Unauthorized' });
try { const decoded = jwt.verify(token, SECRET_KEY) as JwtPayload; (req as any).user =