npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

simple-jwt-id

v1.0.0-beta.1

Published

A lightweight JWT library with multiple algorithm support and token revocation

Readme

simple-jwt-id

npm version npm downloads license CI Coverage

🔐 A lightweight JWT (JSON Web Token) library for Node.js with multiple algorithm support, token revocation, and zero configuration. Think of it as a simple yet powerful JWT handler with built-in blacklist support.


✨ Features

  • Create and verify JWT tokens with ease
  • Refresh token support with automatic rotation
  • Support for multiple algorithms: HS256, HS512, RS256, RS512, PS256, ES256
  • Built-in token revocation with automatic blacklist management
  • Standard JWT claims: iat, exp, nbf, aud, iss, sub, jti
  • Decode tokens without verification
  • Custom error classes for better error handling
  • TypeScript definitions included
  • Works with both CommonJS and ES Modules
  • Minimal dependencies (only simple-cache-id for blacklist)

📦 Installation

npm install simple-jwt-id

🚀 Usage

Basic Usage (CommonJS)

const { createToken, verifyToken, decodeToken } = require("simple-jwt-id");

const SECRET = "your-secret-key";

(async () => {
  // Create a token
  const token = await createToken(
    { userId: 123, username: "john_doe" },
    SECRET,
    { expiresIn: 3600 } // 1 hour
  );

  console.log("Token:", token);

  // Verify token
  const payload = await verifyToken(token, SECRET);
  console.log("Payload:", payload);

  // Decode without verification
  const decoded = decodeToken(token);
  console.log("Decoded:", decoded);
})();

ES Modules

import { createToken, verifyToken, decodeToken } from "simple-jwt-id";

const SECRET = "your-secret-key";

// Create token with custom claims
const token = await createToken({ userId: 789, role: "admin" }, SECRET, {
  algorithm: "HS512",
  expiresIn: 7200, // 2 hours
  issuer: "my-app",
  audience: "my-api",
});

// Verify with validation
const payload = await verifyToken(token, SECRET, {
  audience: "my-api",
  issuer: "my-app",
});

Token Revocation

const { createToken, verifyToken, revokeToken } = require("simple-jwt-id");

const SECRET = "your-secret-key";

(async () => {
  // Create token
  const token = await createToken({ userId: 456 }, SECRET);

  // Verify - works fine
  await verifyToken(token, SECRET);

  // Revoke token
  await revokeToken(token);

  // Verify again - throws error
  try {
    await verifyToken(token, SECRET);
  } catch (error) {
    console.log(error.message); // "Token revoked"
  }
})();

Refresh Token (Access + Refresh Token Pair)

const {
  createTokenPair,
  refreshTokens,
  verifyToken,
} = require("simple-jwt-id");

const SECRET = "your-secret-key";

(async () => {
  // Step 1: Login - Create token pair
  const { accessToken, refreshToken } = await createTokenPair(
    { userId: 123, role: "admin" },
    SECRET,
    {
      accessExpiresIn: 900, // 15 minutes
      refreshExpiresIn: 604800, // 7 days
    }
  );

  console.log("Access Token:", accessToken);
  console.log("Refresh Token:", refreshToken);

  // Step 2: Use access token for API calls
  const payload = await verifyToken(accessToken, SECRET, {
    audience: "api",
  });
  console.log("Verified:", payload);

  // Step 3: When access token expires, refresh it
  const {
    accessToken: newAccessToken,
    refreshToken: newRefreshToken,
  } = await refreshTokens(refreshToken, SECRET);

  console.log("New Access Token:", newAccessToken);
  console.log("New Refresh Token:", newRefreshToken);

  // Step 4: Old refresh token is now revoked (rotation enabled by default)
  try {
    await verifyToken(refreshToken, SECRET, { audience: "refresh" });
  } catch (error) {
    console.log(error.message); // "Token revoked"
  }
})();

Refresh Token Without Rotation

const { createTokenPair, refreshTokens } = require("simple-jwt-id");

const SECRET = "your-secret-key";

(async () => {
  // Create token pair
  const { refreshToken } = await createTokenPair(
    { userId: 456 },
    SECRET
  );

  // Refresh without rotation - old refresh token remains valid
  const { accessToken } = await refreshTokens(refreshToken, SECRET, {
    rotateRefreshToken: false,
  });

  console.log("New Access Token:", accessToken);

  // Old refresh token can still be used
  const result = await refreshTokens(refreshToken, SECRET, {
    rotateRefreshToken: false,
  });
  console.log("Another Access Token:", result.accessToken);
})();

Advanced Usage

const {
  createToken,
  verifyToken,
  decodeToken,
  TokenExpiredError,
  NotBeforeError,
} = require("simple-jwt-id");

const SECRET = "your-secret-key";

(async () => {
  // Token with notBefore claim
  const token = await createToken({ action: "verify-email" }, SECRET, {
    expiresIn: 600, // 10 minutes
    notBefore: 60, // Valid after 1 minute
    subject: "[email protected]",
  });

  // Try to use immediately - throws NotBeforeError
  try {
    await verifyToken(token, SECRET);
  } catch (error) {
    if (error instanceof NotBeforeError) {
      console.log("Token not yet valid!");
    }
  }

  // Decode with complete info
  const { header, payload } = decodeToken(token, { complete: true });
  console.log("Algorithm:", header.alg);
  console.log("Subject:", payload.sub);

  // Ignore expiration (useful for debugging)
  const expiredToken = await createToken({ test: true }, SECRET, {
    expiresIn: 1,
  });
  await new Promise((resolve) => setTimeout(resolve, 2000));

  // This would throw TokenExpiredError
  // await verifyToken(expiredToken, SECRET);

  // But this works
  const payload = await verifyToken(expiredToken, SECRET, {
    ignoreExpiration: true,
  });
  console.log("Payload:", payload);
})();

🧪 Testing

npm test

Jest is used for testing. All tests must pass before publishing.

Test Coverage:

  • 68 unit tests covering all features
  • Both CommonJS and ES Module tests
  • Token creation, verification, decoding, and revocation
  • Refresh token functionality with rotation
  • Error handling and edge cases
  • Complete auth flow integration tests

📂 Project Structure

src/          → main source code
  ├── index.js    → CommonJS version
  └── index.mjs   → ES Module version
test/         → jest test suite
  ├── test-require.test.js  → CommonJS tests
  └── test-import.test.mjs  → ES Module tests
examples/     → usage examples
  ├── example-require.js    → CommonJS example
  └── example-import.mjs    → ES Module example
index.d.ts    → TypeScript definitions

📜 API

createToken(payload, secret, options?)

Create a new JWT token.

Parameters:

  • payload (object): The payload data to include in the token
  • secret (string | Buffer): Secret key or private key for signing
  • options (object, optional):
    • algorithm (string): Algorithm to use - HS256, HS512, RS256, RS512, PS256, ES256 (default: HS256)
    • expiresIn (number): Token expiration time in seconds (default: 3600)
    • notBefore (number): Token not valid before this time offset in seconds
    • audience (string): Intended audience for the token
    • issuer (string): Token issuer
    • subject (string): Token subject

Returns: Promise resolving to the signed JWT token string

Example:

const token = await createToken({ userId: 123, role: "admin" }, "secret-key", {
  algorithm: "HS256",
  expiresIn: 7200, // 2 hours
  issuer: "my-app",
  audience: "my-api",
  subject: "user-authentication",
});

verifyToken(token, secret, options?)

Verify and validate a JWT token.

Parameters:

  • token (string): The JWT token to verify
  • secret (string | Buffer): Secret key or public key for verification
  • options (object, optional):
    • ignoreExpiration (boolean): If true, ignores token expiration (default: false)
    • audience (string): Expected audience to validate against
    • issuer (string): Expected issuer to validate against

Returns: Promise resolving to the verified token payload

Throws:

  • JsonWebTokenError: Invalid token format, signature, audience, issuer, or revoked token
  • TokenExpiredError: Token has expired
  • NotBeforeError: Token is not yet valid (nbf claim)

Example:

try {
  const payload = await verifyToken(token, "secret-key", {
    audience: "my-api",
    issuer: "my-app",
  });
  console.log("User ID:", payload.userId);
} catch (error) {
  if (error instanceof TokenExpiredError) {
    console.log("Token expired!");
  } else if (error instanceof NotBeforeError) {
    console.log("Token not yet valid!");
  } else {
    console.log("Invalid token:", error.message);
  }
}

decodeToken(token, options?)

Decode a JWT token without verifying its signature.

Parameters:

  • token (string): The JWT token to decode
  • options (object, optional):
    • complete (boolean): If true, returns both header and payload; if false, returns only payload (default: false)

Returns: The decoded token payload, or { header, payload } if complete is true

Throws:

  • JsonWebTokenError: Invalid token format

Example:

// Decode payload only
const payload = decodeToken(token);
console.log(payload); // { userId: 123, iat: 1234567890, exp: 1234571490, ... }

// Decode with complete info
const { header, payload } = decodeToken(token, { complete: true });
console.log(header); // { alg: 'HS256', typ: 'JWT' }
console.log(payload); // { userId: 123, ... }

revokeToken(token)

Revoke a JWT token by adding it to the blacklist.

Parameters:

  • token (string): The JWT token to revoke

Returns: Promise

Description: Adds the token's jti (JWT ID) to a blacklist cache. The token will remain blacklisted until its expiration time. Uses simple-cache-id for efficient in-memory blacklist management.

Example:

// Revoke a token (e.g., on user logout)
await revokeToken(token);

// Subsequent verification attempts will fail
await verifyToken(token, SECRET); // Throws: "Token revoked"

createTokenPair(payload, secret, options?)

Creates a pair of access and refresh tokens.

Parameters:

  • payload (object): The payload data to include in both tokens
  • secret (string | Buffer): Secret key or private key for signing
  • options (object, optional):
    • algorithm (string): Algorithm to use (default: HS256)
    • accessExpiresIn (number): Access token expiration in seconds (default: 900 - 15 minutes)
    • refreshExpiresIn (number): Refresh token expiration in seconds (default: 604800 - 7 days)
    • accessAudience (string): Audience for access token (default: api)
    • refreshAudience (string): Audience for refresh token (default: refresh)
    • issuer (string): Token issuer
    • subject (string): Token subject

Returns: Promise resolving to { accessToken, refreshToken }

Example:

const { accessToken, refreshToken } = await createTokenPair(
  { userId: 123, role: "admin" },
  "secret-key",
  {
    accessExpiresIn: 900, // 15 minutes
    refreshExpiresIn: 604800, // 7 days
    issuer: "auth-service",
  }
);

refreshTokens(refreshToken, secret, options?)

Refreshes tokens using a valid refresh token.

Parameters:

  • refreshToken (string): The refresh token to use
  • secret (string | Buffer): Secret key or public key for verification
  • options (object, optional):
    • algorithm (string): Algorithm for new tokens (default: HS256)
    • accessExpiresIn (number): New access token expiration (default: 900)
    • refreshExpiresIn (number): New refresh token expiration (default: 604800)
    • accessAudience (string): Audience for access token (default: api)
    • refreshAudience (string): Expected audience for validation (default: refresh)
    • issuer (string): Expected issuer to validate
    • rotateRefreshToken (boolean): Whether to generate new refresh token (default: true)

Returns: Promise resolving to { accessToken, refreshToken? }

Throws:

  • JsonWebTokenError: Invalid or revoked refresh token
  • TokenExpiredError: Refresh token has expired
  • NotBeforeError: Refresh token not yet valid

Example:

// With rotation (default) - returns both tokens
const { accessToken, refreshToken } = await refreshTokens(
  oldRefreshToken,
  "secret-key"
);

// Without rotation - returns only access token
const { accessToken } = await refreshTokens(oldRefreshToken, "secret-key", {
  rotateRefreshToken: false,
});

🔐 Algorithms

HMAC Algorithms (Symmetric)

  • HS256 - HMAC using SHA-256 (default, recommended for most use cases)
  • HS512 - HMAC using SHA-512 (more secure, slightly slower)

Usage:

const token = await createToken(payload, "your-secret-key", {
  algorithm: "HS256",
});

RSA Algorithms (Asymmetric)

  • RS256 - RSASSA-PKCS1-v1_5 using SHA-256
  • RS512 - RSASSA-PKCS1-v1_5 using SHA-512
  • PS256 - RSASSA-PSS using SHA-256

Usage:

const fs = require("fs");
const privateKey = fs.readFileSync("private.pem");
const publicKey = fs.readFileSync("public.pem");

// Sign with private key
const token = await createToken(payload, privateKey, {
  algorithm: "RS256",
});

// Verify with public key
const payload = await verifyToken(token, publicKey);

ECDSA Algorithm (Asymmetric)

  • ES256 - ECDSA using P-256 and SHA-256

Usage:

const token = await createToken(payload, privateKey, {
  algorithm: "ES256",
});

🔑 JWT Claims

Standard Claims (Automatically Managed)

  • jti (JWT ID) - Unique token identifier (auto-generated)
  • iat (Issued At) - Timestamp when token was created (auto-generated)
  • exp (Expiration Time) - Timestamp when token expires (set via expiresIn)

Optional Claims

  • nbf (Not Before) - Token not valid before this timestamp (set via notBefore)
  • aud (Audience) - Intended recipient of the token (set via audience)
  • iss (Issuer) - Token issuer (set via issuer)
  • sub (Subject) - Subject of the token (set via subject)

Example:

const token = await createToken({ userId: 123 }, SECRET, {
  expiresIn: 3600, // exp = iat + 3600
  notBefore: 60, // nbf = iat + 60
  audience: "my-api",
  issuer: "auth-service",
  subject: "user-auth",
});

// Payload will contain:
// {
//   userId: 123,
//   jti: "a1b2c3d4e5f6g7h8",
//   iat: 1234567890,
//   exp: 1234571490,
//   nbf: 1234567950,
//   aud: "my-api",
//   iss: "auth-service",
//   sub: "user-auth"
// }

🛡️ Error Handling

Error Classes

const {
  JsonWebTokenError,
  TokenExpiredError,
  NotBeforeError,
} = require("simple-jwt-id");
  • JsonWebTokenError - Base error class for all JWT errors

    • Invalid token format
    • Invalid signature
    • Invalid audience
    • Invalid issuer
    • Token revoked
  • TokenExpiredError extends JsonWebTokenError

    • Token has expired (current time > exp)
  • NotBeforeError extends JsonWebTokenError

    • Token used before valid time (current time < nbf)

Error Handling Example

try {
  const payload = await verifyToken(token, SECRET);
} catch (error) {
  if (error instanceof TokenExpiredError) {
    // Handle expired token - maybe refresh it
    console.log("Token expired, please login again");
  } else if (error instanceof NotBeforeError) {
    // Handle token not yet valid
    console.log("Token not yet valid, please wait");
  } else if (error instanceof JsonWebTokenError) {
    // Handle other JWT errors
    console.log("Invalid token:", error.message);
  } else {
    // Handle unexpected errors
    console.error("Unexpected error:", error);
  }
}

🗄️ Token Revocation

Token revocation is handled automatically using simple-cache-id for efficient in-memory blacklist management.

How it works:

  1. Each token has a unique jti (JWT ID) claim
  2. When you call revokeToken(), the jti is added to an in-memory blacklist
  3. The blacklist entry expires when the token would naturally expire (based on exp claim)
  4. Verification checks the blacklist before validating the token

Benefits:

  • No database required for basic revocation
  • Automatic cleanup when tokens expire
  • Memory-efficient (only stores JTI, not full token)
  • Optional persistent storage support (via simple-cache-id)

Example Use Cases:

  • User logout
  • Password reset
  • Permission changes
  • Security incidents
// User logs out
await revokeToken(userToken);

// Change user permissions - revoke all existing tokens
await revokeToken(token1);
await revokeToken(token2);
await revokeToken(token3);

// Security incident - revoke compromised token
await revokeToken(compromisedToken);

💡 TypeScript Support

TypeScript definitions are included out of the box!

import {
  createToken,
  verifyToken,
  decodeToken,
  revokeToken,
  type JWTPayload,
  type CreateTokenOptions,
  type VerifyTokenOptions,
  JsonWebTokenError,
  TokenExpiredError,
  NotBeforeError,
} from "simple-jwt-id";

interface UserPayload extends JWTPayload {
  userId: number;
  username: string;
  role: string;
}

const payload: UserPayload = {
  userId: 123,
  username: "john_doe",
  role: "admin",
};

const options: CreateTokenOptions = {
  algorithm: "HS256",
  expiresIn: 3600,
  issuer: "my-app",
};

const token = await createToken(payload, "secret", options);

try {
  const verified = await verifyToken(token, "secret");
  console.log(verified.userId); // TypeScript knows this exists
} catch (error) {
  if (error instanceof TokenExpiredError) {
    console.log("Token expired!");
  }
}

📄 License

MIT © 2025


🙏 Acknowledgments


📚 Resources