Einleitung: Warum OAuth 2.0 und JWT der Standard moderner Autorisierung sind
\nIn der modernen Webentwicklung sind sichere Authentifizierung und Autorisierung kritisch wichtige Komponenten jeder Anwendung. OAuth 2.0 und JWT (JSON Web Tokens) sind zum De-facto-Standard für den Aufbau verteilter Systeme geworden. OAuth 2.0 bietet ein Protokoll für delegierten Zugriff, während JWT ein kompaktes und eigenständiges Token-Format darstellt.
\nIn diesem Artikel werden wir anhand praktischer Beispiele in TypeScript den gesamten Autorisierungszyklus durchgehen: von der Ausstellung von Tokens bis zu deren Validierung und Erneuerung. Sie erfahren, wie Sie API-Endpunkte schützen, Refresh-Tokens implementieren und typische Fehler behandeln.
\n\n1. Grundlegende Projekteinrichtung und Installation der Abhängigkeiten
\nZunächst erstellen wir ein Node.js-Projekt mit TypeScript. Stellen Sie sicher, dass Node.js (Version 18+) und npm installiert sind.
mkdir oauth-jwt-typescript\ncd oauth-jwt-typescript\nnpm init -y\nnpm install express cors dotenv jsonwebtoken bcrypt\nnpm install -D typescript @types/express @types/cors @types/jsonwebtoken @types/bcrypt ts-node nodemon\nnpx tsc --init\nWir konfigurieren die tsconfig.json für die Arbeit mit ES-Modulen und strengen Typen. In die Datei .env fügen wir geheime Schlüssel hinzu:
ACCESS_TOKEN_SECRET=your-super-secret-access-key\nREFRESH_TOKEN_SECRET=your-super-secret-refresh-key\nACCESS_TOKEN_EXPIRES_IN=15m\nREFRESH_TOKEN_EXPIRES_IN=7d\n\n2. Implementierung der Generierung und Verifizierung von JWT-Tokens
\nWir erstellen ein Hilfsprogramm src/utils/jwt.ts für die Arbeit mit Tokens. Wir werden zwei Arten von Tokens verwenden: Access Token (kurzlebig) und Refresh Token (langlebig).
import jwt from 'jsonwebtoken';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\ninterface TokenPayload {\n userId: string;\n email: string;\n role: 'user' | 'admin';\n}\n\nexport const generateAccessToken = (payload: TokenPayload): string => {\n return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET!, {\n expiresIn: process.env.ACCESS_TOKEN_EXPIRES_IN || '15m',\n });\n};\n\nexport const generateRefreshToken = (payload: TokenPayload): string => {\n return jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET!, {\n expiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || '7d',\n });\n};\n\nexport const verifyAccessToken = (token: string): TokenPayload => {\n return jwt.verify(token, process.env.ACCESS_TOKEN_SECRET!) as TokenPayload;\n};\n\nexport const verifyRefreshToken = (token: string): TokenPayload => {\n return jwt.verify(token, process.env.REFRESH_TOKEN_SECRET!) as TokenPayload;\n};\nBeachten Sie: Wir verwenden eine strenge Typisierung für die Payload. Dies stellt sicher, dass die Tokens immer die erforderlichen Felder enthalten.
\n\n3. Erstellung von Middleware zum Schutz von Routen
\nJetzt implementieren wir eine Middleware, die das Vorhandensein und die Gültigkeit des Access Tokens im Authorization-Header überprüft. Wir erstellen src/middleware/auth.ts:
import { Request, Response, NextFunction } from 'express';\nimport { verifyAccessToken } from '../utils/jwt';\n\nexport interface AuthRequest extends Request {\n user?: {\n userId: string;\n email: string;\n role: 'user' | 'admin';\n };\n}\n\nexport const authenticate = (req: AuthRequest, res: Response, next: NextFunction): void => {\n const authHeader = req.headers['authorization'];\n const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN\n\n if (!token) {\n res.status(401).json({ error: 'Access token is required' });\n return;\n }\n\n try {\n const decoded = verifyAccessToken(token);\n req.user = decoded;\n next();\n } catch (error) {\n res.status(403).json({ error: 'Invalid or expired access token' });\n }\n};\n\nexport const authorizeRole = (...roles: string[]) => {\n return (req: AuthRequest, res: Response, next: NextFunction): void => {\n if (!req.user || !roles