JSPM

@smertins27/jwt-auth-manager

1.0.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 8
    • Score
      100M100P100Q54625F
    • License MIT

    Modernes JWT-Management mit Access & Refresh Token Rotation

    Package Exports

    • @smertins27/jwt-auth-manager

    Readme

    @smertins27/jwt-auth-manager

    Modernes JWT-Management-Package mit Access & Refresh Token Rotation für Node.js und Express.

    Features

    • Access & Refresh Token Generation mit automatischer Rotation
    • jose statt jsonwebtoken - Moderne Library für 2025 mit Web Crypto API
    • Refresh Token Rotation mit Reuse Detection zum Schutz vor Token-Diebstahl
    • Express Middleware für automatische Zugriffssteuerung
    • Token Blacklisting für sofortige Revokation (Logout, Sicherheitsvorfälle)
    • TypeScript mit vollständigen Typdefinitionen
    • Konfigurierbare Excluded Endpoints (Login, Public Routes)
    • ESM und CommonJS Support
    • Node.js 18+ kompatibel (getestet mit Node 22 LTS)
    • Sichere Defaults (HS256, kurze Access Token Lifetime)

    Sicherheits-Features

    • Kurze Access Token Lebensdauer (Default: 15 Minuten)
    • Lange Refresh Token Lebensdauer (Default: 7 Tage)
    • Automatische Token Rotation bei jedem Refresh
    • Reuse Detection erkennt kompromittierte Refresh Tokens
    • Algorithm Enforcement - "none" Algorithm wird blockiert
    • Token Expiry Validation mit jose
    • CORS Header Support
    • Flexible Blacklist-Integration (In-Memory, Redis, DB)

    Installation

    npm install @smertins27/jwt-auth-manager jose

    Peer Dependency:

    npm install express

    Schnellstart

    1. Basic Token Generation

    import { JwtTokenManager } from '@smertins27/jwt-auth-manager';
    
    const manager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!,
      accessTokenExpiry: '15m',
      refreshTokenExpiry: '7d',
    });
    
    // Token-Pair generieren (z.B. nach Login)
    const tokens = await manager.generateTokenPair({
      uid: 'user123',
      email: 'user@example.com',
      role: 'admin',
    });
    
    console.log('Access Token:', tokens.accessToken);
    console.log('Refresh Token:', tokens.refreshToken);
    console.log('Expires in:', tokens.expiresIn, 'seconds');

    2. Token Verification

    // Access Token verifizieren
    try {
      const { payload } = await manager.verifyAccessToken(accessToken);
      console.log('User ID:', payload.uid);
      console.log('Role:', payload.role);
    } catch (error) {
      console.error('Invalid token:', error.message);
    }

    3. Express Middleware Setup

    import express from 'express';
    import { JwtTokenManager, createAuthMiddleware } from '@smertins27/jwt-auth-manager';
    
    const app = express();
    const manager = new JwtTokenManager({ secret: process.env.JWT_SECRET! });
    
    // Middleware mit Excluded Endpoints
    const authMiddleware = createAuthMiddleware(
      {
        secret: process.env.JWT_SECRET!,
        excludedEndpoints: [
          { endpoint: '/api/auth/login', methods: ['POST'] },
          { endpoint: '/api/auth/register', methods: ['POST'] },
          { endpoint: '/api/health', methods: ['GET'] },
          { endpoint: new RegExp('^/api/public/.*'), methods: ['GET'] },
        ],
      },
      manager
    );
    
    // Middleware global anwenden
    app.use(authMiddleware);
    
    // Geschützte Route
    app.get('/api/profile', (req, res) => {
      // req.user ist jetzt verfügbar
      res.json({ user: req.user });
    });
    
    app.listen(3000);

    Verwendung

    Komplettes Login-Flow-Beispiel

    import express from 'express';
    import {
      JwtTokenManager,
      RefreshTokenManager,
      MemoryRefreshTokenStore,
      createAuthMiddleware,
    } from '@smertins27/jwt-auth-manager';
    
    const app = express();
    app.use(express.json());
    
    // Manager Setup
    const tokenManager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!,
      accessTokenExpiry: '15m',
      refreshTokenExpiry: '7d',
      issuer: 'my-app',
      audience: 'my-app-users',
    });
    
    const refreshStore = new MemoryRefreshTokenStore();
    const refreshManager = new RefreshTokenManager(tokenManager, refreshStore);
    
    // Auth Middleware
    const authMiddleware = createAuthMiddleware(
      {
        secret: process.env.JWT_SECRET!,
        excludedEndpoints: [
          { endpoint: '/auth/login', methods: ['POST'] },
          { endpoint: '/auth/refresh', methods: ['POST'] },
        ],
      },
      tokenManager
    );
    
    app.use(authMiddleware);
    
    // Login Route
    app.post('/auth/login', async (req, res) => {
      const { username, password } = req.body;
    
      // Hier: Benutzer gegen LDAP/DB validieren
      // z.B. mit @smertins27/ldap-auth-wrapper
      const user = { uid: 'user123', username, role: 'admin' };
    
      // Token-Pair generieren mit Refresh Token Store
      const tokens = await refreshManager.createTokenPair({
        uid: user.uid,
        username: user.username,
        role: user.role,
      });
    
      res.json(tokens);
    });
    
    // Refresh Route
    app.post('/auth/refresh', async (req, res) => {
      const { refreshToken } = req.body;
    
      try {
        // Token rotieren (alter wird invalidiert, neuer generiert)
        const newTokens = await refreshManager.rotateRefreshToken(refreshToken);
        res.json(newTokens);
      } catch (error: any) {
        if (error.code === 'TOKEN_REUSE_DETECTED') {
          // SECURITY: Alle Tokens des Users wurden revoked!
          return res.status(401).json({ error: 'Token reuse detected - please login again' });
        }
        res.status(401).json({ error: error.message });
      }
    });
    
    // Logout Route
    app.post('/auth/logout', async (req, res) => {
      const userId = req.user!.uid;
    
      // Alle Refresh Tokens des Users invalidieren
      await refreshManager.revokeAllTokens(userId);
    
      res.json({ message: 'Logged out successfully' });
    });
    
    // Geschützte Route
    app.get('/api/profile', (req, res) => {
      res.json({
        user: req.user,
        token: req.token, // Original Access Token
      });
    });
    
    app.listen(3000);

    Mit Token Blacklisting (Logout Support)

    import {
      JwtTokenManager,
      createAuthMiddleware,
      MemoryTokenBlacklist,
    } from '@smertins27/jwt-auth-manager';
    
    const blacklist = new MemoryTokenBlacklist();
    
    const tokenManager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!,
    });
    
    // Middleware mit Blacklist
    const authMiddleware = createAuthMiddleware(
      {
        secret: process.env.JWT_SECRET!,
        isBlacklisted: async (token, payload) => {
          return await blacklist.isBlacklisted(token);
        },
      },
      tokenManager
    );
    
    app.use(authMiddleware);
    
    // Logout: Access Token zur Blacklist hinzufügen
    app.post('/auth/logout', async (req, res) => {
      const token = req.token!;
      const payload = req.user!;
    
      // Berechne verbleibende Gültigkeit
      const decoded = tokenManager.decodeToken(token);
      const expirySeconds = (decoded.exp || 0) - Math.floor(Date.now() / 1000);
    
      // Zur Blacklist hinzufügen (nur bis Token abläuft)
      await blacklist.add(token, expirySeconds);
    
      res.json({ message: 'Logged out' });
    });

    Custom Token Extractor

    const authMiddleware = createAuthMiddleware(
      {
        secret: process.env.JWT_SECRET!,
        // Custom Token Extractor (z.B. aus Cookie)
        tokenExtractor: (req) => {
          return req.cookies?.accessToken;
        },
      },
      tokenManager
    );

    Mit unterschiedlichen Algorithmen

    // HMAC (Symmetric)
    const hmacManager = new JwtTokenManager({
      secret: 'your-secret-key',
      algorithm: 'HS256', // oder HS384, HS512
    });
    
    // RSA (Asymmetric) - benötigt Private Key
    import { readFileSync } from 'fs';
    
    const privateKey = readFileSync('./private-key.pem');
    const rsaManager = new JwtTokenManager({
      secret: privateKey,
      algorithm: 'RS256', // oder RS384, RS512
    });
    
    // EdDSA (Modern, empfohlen für neue Projekte)
    const eddsaManager = new JwtTokenManager({
      secret: privateKey, // EdDSA Private Key
      algorithm: 'EdDSA',
    });

    TypeScript Integration mit Custom Payload

    import { TokenPayload } from '@smertins27/jwt-auth-manager';
    
    // Custom Payload Type
    interface MyTokenPayload extends TokenPayload {
      uid: string;
      email: string;
      role: 'admin' | 'user' | 'guest';
      permissions: string[];
    }
    
    // Type-safe Token Generation
    const tokens = await manager.generateTokenPair({
      uid: 'user123',
      email: 'user@example.com',
      role: 'admin',
      permissions: ['read', 'write', 'delete'],
    } as MyTokenPayload);
    
    // Type-safe Verification
    const { payload } = await manager.verifyAccessToken(accessToken);
    const typedPayload = payload as MyTokenPayload;
    
    console.log(typedPayload.permissions); // ✅ TypeScript wei?, dass es ein string[] ist

    NestJS Integration

    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import {
      JwtTokenManager,
      RefreshTokenManager,
      MemoryRefreshTokenStore,
      TokenPair,
    } from '@smertins27/jwt-auth-manager';
    
    @Injectable()
    export class AuthService {
      private tokenManager: JwtTokenManager;
      private refreshManager: RefreshTokenManager;
    
      constructor() {
        this.tokenManager = new JwtTokenManager({
          secret: process.env.JWT_SECRET!,
          accessTokenExpiry: '15m',
          refreshTokenExpiry: '7d',
        });
    
        const refreshStore = new MemoryRefreshTokenStore();
        this.refreshManager = new RefreshTokenManager(this.tokenManager, refreshStore);
      }
    
      async login(userId: string, userData: any): Promise<TokenPair> {
        return await this.refreshManager.createTokenPair({
          uid: userId,
          ...userData,
        });
      }
    
      async refresh(refreshToken: string): Promise<TokenPair> {
        try {
          return await this.refreshManager.rotateRefreshToken(refreshToken);
        } catch (error: any) {
          throw new UnauthorizedException(error.message);
        }
      }
    
      async logout(userId: string): Promise<void> {
        await this.refreshManager.revokeAllTokens(userId);
      }
    }

    NestJS Guard

    import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
    import { JwtTokenManager } from '@smertins27/jwt-auth-manager';
    
    @Injectable()
    export class JwtAuthGuard implements CanActivate {
      private tokenManager: JwtTokenManager;
    
      constructor() {
        this.tokenManager = new JwtTokenManager({
          secret: process.env.JWT_SECRET!,
        });
      }
    
      async canActivate(context: ExecutionContext): Promise<boolean> {
        const request = context.switchToHttp().getRequest();
        const authHeader = request.headers.authorization;
    
        if (!authHeader || !authHeader.startsWith('Bearer ')) {
          return false;
        }
    
        const token = authHeader.slice(7);
    
        try {
          const { payload } = await this.tokenManager.verifyAccessToken(token);
          request.user = payload;
          return true;
        } catch {
          return false;
        }
      }
    }

    Redis Blacklist (Production-Ready)

    import { TokenBlacklist } from '@smertins27/jwt-auth-manager';
    import Redis from 'ioredis';
    
    export class RedisTokenBlacklist implements TokenBlacklist {
      private redis: Redis;
    
      constructor(redisUrl: string) {
        this.redis = new Redis(redisUrl);
      }
    
      async add(token: string, expirySeconds: number): Promise<void> {
        await this.redis.setex(`blacklist:${token}`, expirySeconds, '1');
      }
    
      async isBlacklisted(token: string): Promise<boolean> {
        const result = await this.redis.get(`blacklist:${token}`);
        return result === '1';
      }
    
      async cleanup(): Promise<void> {
        // Redis TTL handled automatically
      }
    }
    
    // Usage
    const blacklist = new RedisTokenBlacklist(process.env.REDIS_URL!);

    PostgreSQL Refresh Token Store

    import { RefreshTokenStore } from '@smertins27/jwt-auth-manager';
    import { Pool } from 'pg';
    
    export class PostgresRefreshTokenStore implements RefreshTokenStore {
      private pool: Pool;
    
      constructor(connectionString: string) {
        this.pool = new Pool({ connectionString });
      }
    
      async save(jti: string, userId: string, expiryDate: Date): Promise<void> {
        await this.pool.query(
          'INSERT INTO refresh_tokens (jti, user_id, expires_at) VALUES ($1, $2, $3)',
          [jti, userId, expiryDate]
        );
      }
    
      async exists(jti: string): Promise<boolean> {
        const result = await this.pool.query(
          'SELECT 1 FROM refresh_tokens WHERE jti = $1 AND expires_at > NOW()',
          [jti]
        );
        return result.rowCount > 0;
      }
    
      async invalidate(jti: string): Promise<void> {
        await this.pool.query('DELETE FROM refresh_tokens WHERE jti = $1', [jti]);
      }
    
      async invalidateAllForUser(userId: string): Promise<void> {
        await this.pool.query('DELETE FROM refresh_tokens WHERE user_id = $1', [userId]);
      }
    }
    
    // Database Schema
    /*
    CREATE TABLE refresh_tokens (
      jti VARCHAR(64) PRIMARY KEY,
      user_id VARCHAR(255) NOT NULL,
      expires_at TIMESTAMP NOT NULL,
      created_at TIMESTAMP DEFAULT NOW()
    );
    
    CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
    CREATE INDEX idx_refresh_tokens_expires_at ON refresh_tokens(expires_at);
    */

    Environment Variables Best Practice

    import { JwtTokenManager } from '@smertins27/jwt-auth-manager';
    
    const tokenManager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!,
      algorithm: (process.env.JWT_ALGORITHM as any) || 'HS256',
      accessTokenExpiry: process.env.JWT_ACCESS_EXPIRY || '15m',
      refreshTokenExpiry: process.env.JWT_REFRESH_EXPIRY || '7d',
      issuer: process.env.JWT_ISSUER || 'my-app',
      audience: process.env.JWT_AUDIENCE || 'my-app-users',
    });

    .env Beispiel:

    JWT_SECRET=your-super-secret-key-min-32-chars
    JWT_ALGORITHM=HS256
    JWT_ACCESS_EXPIRY=15m
    JWT_REFRESH_EXPIRY=7d
    JWT_ISSUER=my-app
    JWT_AUDIENCE=my-app-users

    API

    JwtTokenManager

    Hauptklasse für Token-Generation und -Verification.

    Constructor

    new JwtTokenManager(config: JwtConfig)

    JwtConfig:

    interface JwtConfig {
      secret: string | Uint8Array;
      algorithm?: 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512' | 'EdDSA';
      accessTokenExpiry?: string; // Default: '15m'
      refreshTokenExpiry?: string; // Default: '7d'
      issuer?: string;
      audience?: string;
    }

    Methoden

    generateTokenPair(payload: TokenPayload): Promise<TokenPair>

    Generiert Access + Refresh Token Pair.

    Returns:

    interface TokenPair {
      accessToken: string;
      refreshToken: string;
      expiresIn: number; // Seconds
    }
    generateAccessToken(payload: TokenPayload): Promise<string>

    Generiert nur einen Access Token.

    verifyAccessToken(token: string): Promise<VerifiedToken<TokenPayload>>

    Verifiziert Access Token und gibt Payload zurück.

    verifyRefreshToken(token: string): Promise<VerifiedToken<RefreshTokenPayload>>

    Verifiziert Refresh Token und gibt Payload zurück.

    decodeToken(token: string): JWTPayload

    Dekodiert Token ohne Verification (nur für Debugging!).


    RefreshTokenManager

    Manager für Refresh Token Rotation.

    Constructor

    new RefreshTokenManager(tokenManager: JwtTokenManager, tokenStore: RefreshTokenStore)

    Methoden

    createTokenPair(payload: TokenPayload): Promise<TokenPair>

    Erstellt Token Pair und speichert Refresh Token im Store.

    rotateRefreshToken(refreshToken: string): Promise<TokenPair>

    Rotiert Refresh Token (alter wird invalidiert, neuer generiert).

    Wirft Fehler bei Token Reuse Detection!

    revokeAllTokens(userId: string): Promise<void>

    Invalidiert alle Refresh Tokens eines Users.


    createAuthMiddleware(config: MiddlewareConfig, tokenManager: JwtTokenManager)

    Erstellt Express Middleware für automatische Token-Verification.

    MiddlewareConfig:

    interface MiddlewareConfig {
      secret: string | Uint8Array;
      algorithm?: JwtConfig['algorithm'];
      excludedEndpoints?: ExcludedEndpoint[];
      tokenExtractor?: (req: Request) => string | undefined;
      isBlacklisted?: (token: string, payload: TokenPayload) => Promise<boolean>;
      corsOrigin?: string; // Default: '*'
    }
    
    interface ExcludedEndpoint {
      endpoint: string | RegExp;
      methods: HttpMethod[];
    }

    Erweitert Request Objekt:

    interface AuthRequest extends Request {
      user?: TokenPayload;
      token?: string;
    }

    Interfaces

    TokenBlacklist

    Interface für Blacklist-Implementierung.

    interface TokenBlacklist {
      add(token: string, expirySeconds: number): Promise<void>;
      isBlacklisted(token: string): Promise<boolean>;
      cleanup?(): Promise<void>;
    }

    Provided Implementations:

    • MemoryTokenBlacklist - In-Memory (Development)

    RefreshTokenStore

    Interface für Refresh Token Persistence.

    interface RefreshTokenStore {
      save(jti: string, userId: string, expiryDate: Date): Promise<void>;
      exists(jti: string): Promise<boolean>;
      invalidate(jti: string): Promise<void>;
      invalidateAllForUser(userId: string): Promise<void>;
    }

    Provided Implementations:

    • MemoryRefreshTokenStore - In-Memory (Development)

    Sicherheits-Best-Practices

    1. Secret Key Sicherheit

    // FALSCH - Hardcoded Secret
    const manager = new JwtTokenManager({ secret: 'mysecret' });
    
    // RICHTIG - Environment Variable mit mind. 32 Zeichen
    const manager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!, // min. 32 chars!
    });

    Secret generieren:

    node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

    2. Token Lifetimes

    // ✅ Empfohlene Werte
    const manager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!,
      accessTokenExpiry: '15m', // Max 30 Min
      refreshTokenExpiry: '7d', // Max 14 Tage
    });

    3. HTTPS Only

    Access Tokens sollten nur über HTTPS übertragen werden!

    // Express HTTPS Enforcement
    app.use((req, res, next) => {
      if (process.env.NODE_ENV === 'production' && !req.secure) {
        return res.redirect('https://' + req.headers.host + req.url);
      }
      next();
    });

    4. Token Storage (Client-Side)

    Empfehlung:

    • Access Token: Memory (JavaScript Variable)
    • Refresh Token: HttpOnly Cookie oder Secure Storage
    // Server-side: Refresh Token als HttpOnly Cookie
    app.post('/auth/login', async (req, res) => {
      const tokens = await refreshManager.createTokenPair(payload);
    
      res.cookie('refreshToken', tokens.refreshToken, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'strict',
        maxAge: 7 * 24 * 60 * 60 * 1000, // 7 Tage
      });
    
      res.json({ accessToken: tokens.accessToken });
    });

    5. Refresh Token Rotation

    Immer Refresh Token Rotation verwenden!

    // ✅ RICHTIG - Mit Rotation
    const newTokens = await refreshManager.rotateRefreshToken(oldToken);
    
    // ❌ FALSCH - Kein Rotation
    const newAccess = await tokenManager.generateAccessToken(payload);

    6. Algorithm Enforcement

    // ✅ RICHTIG - Algorithm spezifiziert
    const manager = new JwtTokenManager({
      secret: process.env.JWT_SECRET!,
      algorithm: 'HS256', // Explizit!
    });
    
    // Das Package blockiert automatisch "none" Algorithm

    Troubleshooting

    Problem: "Invalid token signature"

    Ursache: Secret Key stimmt nicht überein

    Lösung:

    • Überprüfe JWT_SECRET Environment Variable
    • Stelle sicher, dass derselbe Secret für Sign und Verify verwendet wird

    Problem: "Token has expired"

    Ursache: Access Token ist abgelaufen

    Lösung:

    • Verwende Refresh Token um neues Token-Pair zu holen
    • Implementiere automatisches Token Refresh im Client
    // Client-side Auto-Refresh
    async function fetchWithAuth(url: string, options: RequestInit = {}) {
      let token = getAccessToken();
    
      const response = await fetch(url, {
        ...options,
        headers: {
          ...options.headers,
          Authorization: `Bearer ${token}`,
        },
      });
    
      // Wenn 401, versuche Refresh
      if (response.status === 401) {
        const newTokens = await refreshAccessToken();
        setAccessToken(newTokens.accessToken);
    
        // Retry mit neuem Token
        return fetch(url, {
          ...options,
          headers: {
            ...options.headers,
            Authorization: `Bearer ${newTokens.accessToken}`,
          },
        });
      }
    
      return response;
    }

    Problem: "Token reuse detected"

    Ursache: Refresh Token wurde mehrfach verwendet (möglicher Angriff!)

    Lösung:

    • User muss sich neu einloggen
    • Alle Tokens wurden aus Sicherheitsgründen revoked

    Problem: TypeScript Errors mit req.user

    Ursache: Express Request Type nicht erweitert

    Lösung:

    // types/express.d.ts
    import { TokenPayload } from '@smertins27/jwt-auth-manager';
    
    declare global {
      namespace Express {
        interface Request {
          user?: TokenPayload;
          token?: string;
        }
      }
    }
    
    export {};

    Migration von jsonwebtoken

    Falls du von jsonwebtoken migrierst:

    Vorher (jsonwebtoken)

    import jwt from 'jsonwebtoken';
    
    const token = jwt.sign({ uid: 'user123' }, 'secret', { expiresIn: '15m' });
    const payload = jwt.verify(token, 'secret');

    Nachher (jwt-auth-manager)

    import { JwtTokenManager } from '@smertins27/jwt-auth-manager';
    
    const manager = new JwtTokenManager({
      secret: 'secret',
      accessTokenExpiry: '15m',
    });
    
    const token = await manager.generateAccessToken({ uid: 'user123' });
    const { payload } = await manager.verifyAccessToken(token);

    Vorteile:

    • Async/await statt Callbacks
    • Web Crypto API (schneller)
    • Bessere TypeScript-Unterstützung
    • ESM-first
    • Eingebaute Refresh Token Rotation
    • Middleware inklusive

    Kompatibilität

    • Node.js: >= 18.0.0 (getestet mit Node 22 LTS)
    • TypeScript: >= 5.0.0
    • Express: ^4.18.0 || ^5.0.0

    Abhängigkeiten

    • jose: ^5.9.0

    Peer Dependencies

    • express: ^4.18.0 || ^5.0.0

    Development

    # Repository klonen
    git clone https://github.com/dein-username/jwt-auth-manager.git
    cd jwt-auth-manager
    
    # Dependencies installieren
    npm install
    
    # Build
    npm run build
    
    # Tests
    npm test
    
    # Watch-Modus
    npm run dev

    Contributing

    Contributions sind willkommen! Bitte:

    1. Fork das Repository
    2. Erstelle einen Feature-Branch (git checkout -b feature/AmazingFeature)
    3. Commit deine Änderungen (git commit -m 'Add AmazingFeature')
    4. Push zum Branch (git push origin feature/AmazingFeature)
    5. Öffne einen Pull Request

    Lizenz

    MIT License - siehe LICENSE Datei für Details.

    Support

    Bei Fragen oder Problemen:

    Changelog

    1.0.0 (2025-10-30)

    • Initial Release
    • JWT Token Generation & Verification mit jose
    • Refresh Token Rotation mit Reuse Detection
    • Express Middleware
    • Token Blacklisting Support
    • In-Memory Stores für Development
    • TypeScript Definitionen
    • ESM + CommonJS Support
    • Vollständige Dokumentation

    Verwandte Packages

    Danksagungen

    Basiert auf jose - dem modernen JWT-Standard für JavaScript.


    Sicherheitshinweis: Dieses Package implementiert moderne JWT Best Practices für 2025. Bitte verwende in Produktion:

    • Sichere Secret Keys (min. 32 Zeichen)
    • HTTPS-only Token-Übertragung
    • Kurze Access Token Lifetimes
    • Persistente Refresh Token Stores (Redis/DB)
    • Persistente Blacklists (Redis/DB)
    • Regelmä?ige Security-Audits