New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

crypto-token-kit

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

crypto-token-kit

A modular, encrypted, DB-agnostic token system with optional refresh token support. Built as a secure alternative to JWT with built-in session management, revocation, and rotation capabilities.

latest
npmnpm
Version
1.0.2
Version published
Maintainers
1
Created
Source

Crypto-token-kit

DEPRECATED — Please use @compyai/securetoken

A minimal, modular, and encrypted session token system designed as a secure alternative to JWT.
Supports optional refresh tokens with revocation and pluggable session storage.
Includes optional IP and fingerprint binding for enhanced security.

🚀 Features

  • 🔐 Strong Encryption: AES-256-GCM encryption + HMAC-SHA512 signing for robust token security
  • 🔁 Refresh Tokens: Optional refresh token support with automatic rotation and revocation
  • 🧩 Pluggable Storage: Modular session store interface (in-memory, Redis, or custom implementations)
  • 🛠️ Flexible Sessions: Stateless or hybrid session control options
  • 🌐 Enhanced Security: Optional IP & fingerprint binding and verification to harden tokens
  • Lightweight: Minimal dependencies with maximum security
  • 🔄 Token Rotation: Automatic token refresh with revocation of old tokens
  • 🚫 Revocation Support: Built-in token and session revocation capabilities

📦 Installation

npm install crypto-token-kit dotenv

If using Redis store:

npm install ioredis

⚙️ Setup Environment Variables

Create a .env file in your project root:

STK_ENC_KEY=your_32_byte_hex_key_here
STK_HMAC_KEY=your_64_byte_hex_key_here

🔑 Generate Secure Keys

Run this command to generate cryptographically strong keys:

node -e "console.log('STK_ENC_KEY=' + require('crypto').randomBytes(32).toString('hex')); console.log('STK_HMAC_KEY=' + require('crypto').randomBytes(64).toString('hex'))"

Copy the output and paste it into your .env file.

🛠️ Usage Examples

Basic Usage

const {
  createToken,
  verifyToken,
  refreshToken,
  registerStore,
} = require("crypto-token-kit");

const memoryStore = require("crypto-token-kit/stores/memoryStore");
registerStore(memoryStore);

async function basicExample() {
  // Create a simple access token
  const { accessToken } = await createToken(
    { userId: "user-123", role: "admin" },
    { expiresIn: 900 } // 15 minutes
  );

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

  // Verify the token
  const payload = await verifyToken(accessToken);
  console.log("Verified Payload:", payload);
}

basicExample().catch(console.error);

Advanced Usage with Refresh Tokens and Security Binding

async function advancedExample() {
  // Create token with refresh support and security binding
  const { accessToken, refreshToken: refresh } = await createToken(
    { userId: "user-123", email: "user@example.com" },
    {
      refresh: true,
      expiresIn: 900, // 15 minutes for access token
      refreshExpiresIn: 2592000, // 30 days for refresh token
      bindIp: true,
      bindFingerprint: true,
      ip: "203.0.113.42",
      fingerprint: "browser-fingerprint-string",
    }
  );

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

  // Verify token with security checks
  try {
    const payload = await verifyToken(accessToken, {
      checkIp: true,
      ip: "203.0.113.42",
      checkFingerprint: true,
      fingerprint: "browser-fingerprint-string",
    });
    console.log("Verified Payload:", payload);
  } catch (error) {
    console.error("Token verification failed:", error.message);
  }

  // Refresh tokens when access token expires
  try {
    const newTokens = await refreshToken(refresh, {
      checkIp: true,
      ip: "203.0.113.42",
      checkFingerprint: true,
      fingerprint: "browser-fingerprint-string",
    });

    console.log("New Access Token:", newTokens.accessToken);
    console.log("New Refresh Token:", newTokens.refreshToken);
  } catch (error) {
    console.error("Token refresh failed:", error.message);
  }
}

advancedExample().catch(console.error);

Express.js Middleware Example

const express = require("express");
const { verifyToken } = require("crypto-token-kit");

const app = express();

// Authentication middleware
const authenticate = async (req, res, next) => {
  const token = req.headers.authorization?.replace("Bearer ", "");

  if (!token) {
    return res.status(401).json({ error: "No token provided" });
  }

  try {
    const payload = await verifyToken(token, {
      checkIp: true,
      ip: req.ip,
      checkFingerprint: true,
      fingerprint: req.headers["x-fingerprint"],
    });

    req.user = payload;
    next();
  } catch (error) {
    res.status(401).json({ error: "Invalid token" });
  }
};

// Protected route
app.get("/profile", authenticate, (req, res) => {
  res.json({ user: req.user });
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

🔌 Store Interface

Built-in Stores

Memory Store (Development)

const memoryStore = require("crypto-token-kit/stores/memoryStore");
registerStore(memoryStore);

Redis Store (Production)

const redisStore = require("crypto-token-kit/stores/redisStore");
registerStore(redisStore);

Custom Store Implementation

Your custom store should implement these async methods:

class CustomStore {
  async saveRefresh(refreshId, data) {
    // Save refresh token data
    // data: { userId, expiresAt, ip?, fingerprint? }
  }

  async isRefreshRevoked(refreshId) {
    // Return true if refresh token is revoked
    return false;
  }

  async revokeRefresh(refreshId) {
    // Mark refresh token as revoked
  }

  // Optional: Session management
  async saveSession(sessionId, data) {
    // Save session data
  }

  async isSessionRevoked(sessionId) {
    // Return true if session is revoked
    return false;
  }

  async revokeSession(sessionId) {
    // Mark session as revoked
  }
}

const customStore = new CustomStore();
registerStore(customStore);

📚 API Reference

createToken(payload, options)

Creates a new access token and optionally a refresh token.

Parameters:

  • payload (Object): Data to include in the token
  • options (Object): Configuration options

Options:

  • expiresIn (Number): Access token expiration in seconds (default: 900)
  • refresh (Boolean): Generate refresh token (default: false)
  • refreshExpiresIn (Number): Refresh token expiration in seconds (default: 2592000)
  • bindIp (Boolean): Bind token to IP address (default: false)
  • bindFingerprint (Boolean): Bind token to fingerprint (default: false)
  • ip (String): IP address to bind to (required if bindIp is true)
  • fingerprint (String): Fingerprint to bind to (required if bindFingerprint is true)

Returns: Promise<{ accessToken, refreshToken? }>

verifyToken(token, options)

Verifies and decodes a token.

Parameters:

  • token (String): The token to verify
  • options (Object): Verification options

Options:

  • checkIp (Boolean): Verify IP binding (default: false)
  • checkFingerprint (Boolean): Verify fingerprint binding (default: false)
  • ip (String): Current IP address (required if checkIp is true)
  • fingerprint (String): Current fingerprint (required if checkFingerprint is true)

Returns: Promise<Object> - Decoded payload

refreshToken(refreshToken, options)

Refreshes an access token using a refresh token.

Parameters:

  • refreshToken (String): The refresh token
  • options (Object): Same options as verifyToken

Returns: Promise<{ accessToken, refreshToken }>

revokeToken(refreshToken)

Revokes a refresh token.

Parameters:

  • refreshToken (String): The refresh token to revoke

Returns: Promise<void>

🔒 Security Features

Encryption & Signing

  • AES-256-GCM: Authenticated encryption for token contents
  • HMAC-SHA512: Message authentication for token integrity
  • Separate Keys: Different keys for encryption and signing

IP Binding

Tokens can be bound to specific IP addresses to prevent token theft:

const { accessToken } = await createToken(payload, {
  bindIp: true,
  ip: "203.0.113.42",
});

// Verification will fail if IP doesn't match
await verifyToken(accessToken, {
  checkIp: true,
  ip: "203.0.113.42", // Must match bound IP
});

Fingerprint Binding

Tokens can be bound to browser/device fingerprints:

const { accessToken } = await createToken(payload, {
  bindFingerprint: true,
  fingerprint: "unique-browser-fingerprint",
});

Automatic Token Rotation

Refresh tokens are automatically rotated on each use, invalidating the old token:

const newTokens = await refreshToken(oldRefreshToken);
// oldRefreshToken is now invalid

🧪 Testing

Run the built-in test suite:

node tests/basic.test.js

Create Your Own Tests

const assert = require("assert");
const { createToken, verifyToken } = require("crypto-token-kit");

async function runTests() {
  // Test token creation and verification
  const { accessToken } = await createToken({ userId: "test" });
  const payload = await verifyToken(accessToken);

  assert.strictEqual(payload.userId, "test");
  console.log("✓ Basic token test passed");

  // Test IP binding
  const { accessToken: boundToken } = await createToken(
    { userId: "test" },
    { bindIp: true, ip: "127.0.0.1" }
  );

  try {
    await verifyToken(boundToken, { checkIp: true, ip: "192.168.1.1" });
    assert.fail("Should have failed IP check");
  } catch (error) {
    console.log("✓ IP binding test passed");
  }
}

runTests().catch(console.error);

🚦 Error Handling

The library throws descriptive errors for different failure scenarios:

try {
  await verifyToken(invalidToken);
} catch (error) {
  switch (error.code) {
    case "TOKEN_EXPIRED":
      console.log("Token has expired");
      break;
    case "TOKEN_INVALID":
      console.log("Token is malformed or tampered");
      break;
    case "IP_MISMATCH":
      console.log("Token IP binding failed");
      break;
    case "FINGERPRINT_MISMATCH":
      console.log("Token fingerprint binding failed");
      break;
    case "TOKEN_REVOKED":
      console.log("Token has been revoked");
      break;
    default:
      console.log("Unknown error:", error.message);
  }
}

🔄 Migration from JWT

If you're migrating from JWT, here's a comparison:

FeatureJWTcrypto-token-kit
EncryptionNone (signed only)AES-256-GCM
Token SizeLargeCompact
RevocationComplex/ImpossibleBuilt-in
Refresh TokensManual implementationBuilt-in
IP/Fingerprint BindingManualBuilt-in
Session StorageStateless onlyPluggable

Example Migration

Before (JWT):

const jwt = require("jsonwebtoken");
const token = jwt.sign(payload, secret, { expiresIn: "15m" });
const decoded = jwt.verify(token, secret);

After (crypto-token-kit):

const { createToken, verifyToken } = require("crypto-token-kit");
const { accessToken } = await createToken(payload, { expiresIn: 900 });
const decoded = await verifyToken(accessToken);

📄 License

MIT License - see LICENSE file for details.

Made with ❤️ for secure applications

Keywords

token

FAQs

Package last updated on 28 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts