Skip to content

Token Management

Azizul Hakim edited this page Nov 1, 2024 · 1 revision

Overview

The nestjs-xsecurity module uses a secure token-based system with the following features:

  • Short-lived tokens (10 seconds by default)
  • HMAC-SHA256 signing
  • Base64 encoded payload
  • Expiry timestamp validation

Token Structure

Each security token consists of two parts separated by a period:

base64(payload).signature
  1. Payload: Base64 encoded JSON containing:

    {
      "expiry": 1234567890  // Unix timestamp in seconds
    }
  2. Signature: HMAC-SHA256 hash of the encoded payload using the secret key

Token Generation

Using the Official Generator Functions

TypeScript/JavaScript

import crypto from 'crypto';

function generateXSecurityToken(secretKey: string, expirySeconds = 10): string {
  const expiryTimestamp = Math.floor(Date.now() / 1000) + expirySeconds;
  const payload = { expiry: expiryTimestamp };
  const token = Buffer.from(JSON.stringify(payload)).toString('base64');
  const signature = crypto
    .createHmac('sha256', secretKey)
    .update(token)
    .digest('hex');

  return `${token}.${signature}`;
}

Token Lifecycle

graph LR
    A[Generate Token] --> B[Send Request]
    B --> C{Valid?}
    C -->|Yes| D[Process Request]
    C -->|No| E[Return 403]
    E --> A
Loading

Token Validation Process

The middleware performs the following validations:

  1. Format Check

    const parts = token.split('.');
    if (parts.length !== 2) return false;
  2. Signature Verification

    const [token, signature] = parts;
    const expectedSignature = crypto
      .createHmac('sha256', secretKey)
      .update(token)
      .digest('hex');
    
    if (!crypto.timingSafeEqual(
      Buffer.from(expectedSignature),
      Buffer.from(signature)
    )) {
      return false;
    }
  3. Expiry Validation

    const payload = JSON.parse(Buffer.from(token, 'base64').toString());
    if (!payload.expiry) return false;
    
    const now = Date.now() / 1000;
    return now < payload.expiry && 
           payload.expiry <= now + maxExpirySeconds;

Related Topics

Clone this wiki locally