Prefixed API token generation, SHA-256 hashing, and scope validation. Zero dependencies, Web Crypto API.
Works in Cloudflare Workers, Node.js 20+, Deno, Bun, and browsers.
npm install @arraypress/api-tokensimport { generateToken, hashToken, isValidToken, hasScope } from '@arraypress/api-tokens';
// Generate a token
const token = generateToken(); // 'sc_pat_aBcDeFgHiJkLmNoPqR...'
// Hash for storage (never store raw tokens)
const hash = await hashToken(token);
// Return token to user once, store only the hash
await db.insert({ token_hash: hash, scopes: ['content:read'] });
// Later: validate incoming token
const incomingHash = await hashToken(request.headers.get('Authorization').slice(7));
const row = await db.findByHash(incomingHash);
if (row && hasScope(row.scopes, 'content:read')) {
// Authorized
}Generate a cryptographically random token with prefix. Default: 'sc_pat_' + 32 random bytes.
generateToken(); // 'sc_pat_...'
generateToken('ec_pat_'); // 'ec_pat_...'SHA-256 hash a token for database storage. Returns base64url string. Never store raw tokens.
Extract display prefix for UI (e.g. 'sc_pat_aBcDeFgH'). Shows prefix + first 8 chars.
Validate token format — correct prefix, base64url body, minimum length.
Auto-detect the prefix from a token string (e.g. 'sc_pat_' from 'sc_pat_abc...').
Check that all requested scopes are in the allowed set. Returns boolean.
const VALID = ['content:read', 'content:write', 'media:read', 'admin'];
validateScopes(['content:read', 'media:read'], VALID); // true
validateScopes(['content:read', 'unknown'], VALID); // falseCheck if token scopes include the required scope. 'admin' grants everything.
Check if a token is expired. Returns false for null (never expires).
MIT