Skip to content
/ jwt Public

A secure and tested json-web-token class-based utility library for generating keys, signing, verifying, and decoding JWT payloads for use with your high-security demanding projects.

License

Notifications You must be signed in to change notification settings

bepalo/jwt

Repository files navigation

πŸ† @bepalo/jwt

npm version jsr github GitHub Repo stars

license Node.js Bun Deno CI Tests Vitest

A secure and tested json-web-token class-based utility library for generating keys, signing, verifying, and decoding JWT payloads for use with your high-security demanding projects.

Table of Contents

✨ Features

  • 🎯 JWT sign and verify with HMAC, ECDSA, RSA, RSA-PSS algorithms.
  • πŸ—οΈ Easy key generation support.
  • ♻️ Synchronous by default, with asynchronous alternatives.
  • ⌚ Time helper functions from @bepalo/time.
  • πŸ“„ Written in modern TypeScript.
  • πŸ“’ Available for both ESM and CommonJS.
  • πŸ“’ Works with Node, Bun, and Deno.
  • πŸ“’ Built on the crypto API.

πŸš€ Get Started

πŸ“₯ Installation

Node.js / Bun (npm / pnpm / yarn)

bun add @bepalo/jwt
# or
pnpm add @bepalo/jwt
# or
npm install @bepalo/jwt
# or
yarn add @bepalo/jwt

Deno

Import directly using the URL:

import { JWT } from "npm:@bepalo/jwt";
// or
import { JWT } from "jsr:@bepalo/jwt";

πŸš€ Quick Start

Simple Symmetric HMAC:

import { JWT } from "@bepalo/jwt";

// 1. Generate a key
const secret = JWT.genHmac("HS256");

// 2. Store the generated key somewhere safe like in a .env file
console.log(secret);

// 3. Load that key from where it was stored
const signKey = process.env.SECRET;
const verifyKey = process.env.SECRET;

// 4. Create a JWT instance for signing
const jwtSign = JWT.createSymmetric(signKey, "HS256");

// 5. Sign a payload
const token = jwtSign.signSync({ 
  userId: 123, 
  role: "admin", 
  jti: "tid-1234",
  iat: JWT.now(), 
  // exp: JWT.on("2026"),
  // nbf: JWT.after(5).Minutes,
  // ...
});

// 6. Create another JWT instance for verifying. *optional*
const jwtVerify = JWT.createSymmetric(verifyKey, "HS256");

// 7. Verify and decode the token
const { valid, payload, error } = jwtVerify.verifySync(token, {
  jti: "tid-1234",
  nbfLeeway: JWT.for(5).Seconds
});

// 8. Deal with errors or use the payload
console.log(valid);    // true
console.log(payload);  // { userId: 123, role: "admin", ... }
console.log(error);    // undefined

Generic:

import { JWT } from "@bepalo/jwt";

// 1. Generate a key
const key = JWT.genKey("ES256");

// 2. Store the generated key somewhere safe like in a .env file
const { alg, publicKey, privateKey } = key;
console.log(JSON.stringify({ alg, publicKey }));
console.log(JSON.stringify({ alg, privateKey }));

// 3. Load that key from where it was stored
const signKey = JSON.parse(process.env.PRIVATE_KEY ?? "null");
const verifyKey = JSON.parse(process.env.PUBLIC_KEY ?? "null");

// 4. Create a JWT instance for signing
const jwtSign = JWT.create(signKey);

// 5. Sign a payload
const token = jwtSign.signSync({ 
  userId: 123, 
  role: "admin", 
  jti: "tid-1234",
  iat: JWT.now(), 
  // exp: JWT.on("2026"),
  // nbf: JWT.after(5).Minutes,
  // ...
});

// 6. Create a JWT instance for verifying
const jwtVerify = JWT.create(verifyKey);

// 7. Verify and decode the token
const { valid, payload, error } = jwtVerify.verifySync(token, {
  jti: "tid-1234",
  nbfLeeway: JWT.for(5).Seconds
});

// 8. Deal with errors or use the payload
console.log(valid);    // true
console.log(payload);  // { userId: 123, role: "admin", ... }
console.log(error);    // undefined

βœ… Usage

πŸ”‘ Key Creation

import { JWT } from "@bepalo/jwt";

// πŸ“’ Symmetric HMAC key generation. returns string
const secret = JWT.genHmac("HS256");

// πŸ“’ Generic way of generating any key. returns JwtKey
const key = JWT.genKey("none");
const key = JWT.genKey("HS512"); 
const key = JWT.genKey("ES384"); 
const key = JWT.genKey("RS256"); 
const key = JWT.genKey("PS256"); 

πŸ—οΈ JWT Instance Creation

import { JWT } from "@bepalo/jwt";

type Payload = { userId: number, role: "admin" | "user" };

const secret = JWT.genHmac("HS256");
// πŸ“’ Symmetric only way of creating a JWT instance.
const jwt = JWT.createSymmetric<Payload>(secret, "HS256");

const key = JWT.genKey("ES256"); 
// πŸ“’ Generic way of creating a JWT instance
const jwt = JWT.create<Payload>(key);

✍️ Signing

Synchronous:

import { JWT } from "@bepalo/jwt";

type Payload = { userId: number, role: "admin" | "user" };

const key = JWT.genKey("HS256"); 
const jwt = JWT.create<Payload>(key);

// πŸ“’ Sign synchronously
const token = jwt.signSync({ userId: 123, role: "admin", iat: JWT.now() });

Asynchronous:

import { JWT } from "@bepalo/jwt";

type Payload = { userId: number, role: "admin" | "user" };

const key = JWT.genKey("HS256"); 
const jwt = JWT.create<Payload>(key);

// πŸ“’ Sign asynchronously
const token = await jwt.sign({ userId: 123, role: "admin", iat: JWT.now() });

πŸ”Ž Verification

Synchronous:

import { JWT } from "@bepalo/jwt";

type Payload = { userId: number, role: "admin" | "user" };

const key = JWT.genKey("HS256"); 
const jwt = JWT.create<Payload>(key);

const token = jwt.signSync({ userId: 123, role: "admin", iat: JWT.now() });

// πŸ“’ Verify synchronously
const { valid, payload, error } = jwt.verifySync(token);

// πŸ“’ Verify signature synchronously
const { valid, error } = jwt.verifySignatureSync(token);

Asynchronous:

import { JWT } from "@bepalo/jwt";

type Payload = { userId: number, role: "admin" | "user" };

const key = JWT.genKey("HS256"); 
const jwt = JWT.create<Payload>(key);

const token = await jwt.sign({ userId: 123, role: "admin", iat: JWT.now() });

// πŸ“’ Verify asynchronously
const payload = await jwt.verify(token);

// πŸ“’ Verify signature asynchronously
const valid = await jwt.verifySignature(token);

βš™οΈ Verify Options

import { JWT } from "@bepalo/jwt";

type Payload = { userId: number, role: "admin" | "user" };

const key = JWT.genKey("HS256"); 
const jwt = JWT.create<Payload>(key);

const token = await jwt.sign({
  userId: 123, 
  role: "admin", 
  iat: JWT.now(),
  nbf: JWT.after(5).Minutes,
  exp: JWT.on("2026"),
  jti: "jti-1234",
  iss: "auth-server",
  sub: "session",
  aud: ["auth-client-a", "auth-client-b"],
});

const payload = await jwt.verify(token, {
  strict: false, // default: true
  iss: "auth-server",
  aud: "auth-client-a", // or ["auth-client-a", "auth-client-c"]
  sub: "session",
  jti: "jti-1234",
  exp: true, // default: true
  nbf: false, // default: true
  expLeeway: JWT.for(5).Seconds,
  nbfLeeway: JWT.for(5).Seconds,
});

const valid = await jwt.verifySignature(token, { strict: false });

πŸ“š Quick Docs

All errors thrown or returned by this library are instances of JwtError with a descriptive message and a smart error code.

JWT class
// Using Time and RelativeTime for fluent time expression feature.
import type { Time, RelativeTime } from "@bepalo/time";

/**
 * JWT class providing utility function and methods to generate keys, and sign, verify and decode tokens.
 */
class JWT<Payload> {

  // Get the current time in seconds.
  static now(): number;
  
  // Get the given date-time in seconds.
  static on(date): number;

  // Fluently define absolute time in seconds. 
  // eg. `JWT.for(1).Day`
  static for(): Time;
  
  // Fluently define the relative time in seconds. 
  // eg. `JWT.in(10).Hours`
  static in(): RelativeTime;
  
  // Fluently define the relative time in seconds. 
  // eg. `JWT.after(5).Minutes`
  static after(): RelativeTime;

  // Fluently define the relative time in seconds. 
  // eg. `JWT.before(1).Week`
  static before(): RelativeTime;


  // Generate a random key for HMAC
  static genHmac(alg): string;

  // Generate a generic jwt key based on algorithm and optional parameters
  static genKey(alg, options?): Key;

  // Create a JWT instance using a symmetric algorithm.
  static createSymmetric<Payload>(secret, alg): JWT<Payload>;

  // Create a JWT instance using an asymmetric JwtKey.
  static createAsymmetric<Payload>(key): JWT<Payload>;

  // Create a JWT instance using a generic JwtKey.
  static create<Payload>(key): JWT<Payload>;


  // Synchronously sign a payload and return a JWT token string.
  signSync(payload): string

  // Asynchronously sign a payload and return a JWT token string.
  sign(payload): Promise<string>


  // Synchronously verify only the token and the signature (no payload or claims are checked).
  verifySignatureSync(token, verifyJwtStrict?): JwtResult<Payload> 

  // Asynchronously verify only the signature of the token (no claims checked).
  verifySignature(token, verifyJwtStrict?): Promise<boolean>;


  // Synchronously verify a token, signature, payload and claims.
  verifySync(token, verifyJwt?): JwtResult<Payload>;

  // Asynchronously verify a token, signature, payload and claims.
  verify(token, verifyJwt?): Promise<JwtPayload<Payload>>;

}
JWT Error class
/**
 * Error class for use with this JWT library
 */
class JwtError extends Error {
  code: JwtErrorCode;
}
JWT Result type
/**
 * JWT verify result type
 */
type JwtResult<Payload> = {
  valid: boolean;
  payload?: JwtPayload<Payload>;
  error?: JwtError;
};
JWT Key type
/**
 * JWT Key type
 */
type JwtKey = { 
  alg: JwtAlgorithm, 
  publicKey: string; 
  privateKey: string 
};
JWT Verify Options type
/**
 * Optional parameters for verifying a JWT.
 */
type JwtVerifyOptions = {
  // Decoded algorithm must match the stored algorithm. default: true
  strict?: boolean;
  // Expected issuer
  iss?: string;
  // Expected audience/s
  aud?: string | string[];
  // Expected subject
  sub?: string;
  // Expected token id
  jti?: string;
  // Enable/disable expiration time check. default: true
  exp?: boolean;
  // Enable/disable not-before time check. default: true
  nbf?: boolean;
  // Leeway in seconds for expiration time
  expLeeway?: number;
  // Leeway in seconds for not-before time
  nbfLeeway?: number;
};
JWT Algorithm types
// Supported symmetric algorithms
type JwtSymmetricAlgorithm = "HS256" | "HS384" | "HS512";

// Supported asymmetric algorithms
type JwtAsymmetricAlgorithm =
  | "RS256"
  | "RS384"
  | "RS512"
  | "ES256"
  | "ES384"
  | "ES512"
  | "PS256"
  | "PS384"
  | "PS512";

// All supported JWT algorithms
type JwtAlgorithm =
  | JwtSymmetricAlgorithm
  | JwtAsymmetricAlgorithm
  | "none";
JWT Error codes
/**
 * Smart Error codes for use with this JWT library
 */
enum JwtErrorCode {
  internalError = 0,

  invalid = 100,

  tokenInvalid = 110,
  tokenTypeInvalid = 111,

  tokenHeaderInvalid = 120,

  algorithmInvalid = 130,
  algorithmMismatch = 131,

  signatureInvalid = 140,
  signatureMismatch = 141,

  payloadInvalid = 150,

  // for use with your custom validation errors
  claimInvalid = 200,
  claimMismatch = 201,

  jti = 210,
  jtiMismatch = 210,
  jtId = 210,
  jtIdMismatch = 210,

  iss = 220,
  issMismatch = 220,
  issuer = 220,
  issuerMismatch = 220,

  sub = 230,
  subMismatch = 230,
  subjet = 230,
  subjectMismatch = 230,

  aud = 240,
  audMismatch = 240,
  audience = 240,
  audienceMismatch = 240,

  exp = 250,
  expired = 250,

  nbf = 260,
  notValidYet = 260,
  notYetValid = 260,
  notBefore = 260,

  keyInvalid = 300,
  privateKeyInvalid = 301,
  publicKeyInvalid = 302,
};

πŸ›‘οΈ Supported Algorithms

πŸ“• The ES512(P-521) algorithm is less common and might not be supported on the runtime of your preference. But you can use ES256 or ES384, or switch to a runtime that supports it.

HMAC-Based (Symmetric, Fast): Used for shared-key authentication.
  • HS256: Most common and secure.
  • HS384: Slightly stronger but less common.
  • HS512: High-security option for robust applications.
ECDSA-Based (Asymmetric, Efficient): Faster than RSA, great for modern applications.
  • ES256: Recommended alternative to RSA.
  • ES384: Stronger cryptographic security.
  • ES512: Best for ultra-secure environments. NOTE: May not be supported/implemented in all runtimes.
RSA-Based (Asymmetric): Used for OAuth, OpenID, and other key-based authentication.
  • RS256: Widely used.
  • RS384: Stronger but heavier.
  • RS512: Computationally expensive but highly secure.
RSA-PSS (Asymmetric): RSA-PSS variants.
  • PS256: RSA-PSS variant with SHA-256.
  • PS384: RSA-PSS variant with SHA-384.
  • PS512: RSA-PSS variant with SHA-512.

For more details, see RFC 7519 and IANA JWT Algorithms.

πŸ”— Links

@bepalo/time

npm jsr github

πŸ•ŠοΈ Thanks, Stay Safe and Enjoy

If you like this library and want to support then please give a star on GitHub GitHub Repo stars

πŸ’– Be a Sponsor

Fund me so I can give more attention to the products and services you liked.

Ko-fi Badge

About

A secure and tested json-web-token class-based utility library for generating keys, signing, verifying, and decoding JWT payloads for use with your high-security demanding projects.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published