imagic-auth
v1.0.2
Published
Sign and verify JWTs, generate and validate API keys, and check user permissions
Maintainers
Readme
imagic-auth
JWT signing/verification, API key utilities, and permission checking for Node.js.
Install
npm install imagic-authQuick Start
import { sign, verify, generateApiKey, hashApiKey, validateApiKey, hasPermission } from 'imagic-auth'
// JWT
const token = sign({ userId: 42, role: 'admin' }, 'my-secret', { expiresIn: 3600 })
const payload = verify(token, 'my-secret')
// { userId: 42, role: 'admin', iat: 1700000000, exp: 1700003600 }
// API keys
const key = generateApiKey({ prefix: 'sk', length: 32 }) // 'sk_a1b2c3...'
const hash = hashApiKey(key, 'storage-secret')
const ok = validateApiKey(key, hash, 'storage-secret') // true
// Permissions
hasPermission(['users:read', 'users:write'], 'users:read') // true
hasPermission(['*'], 'anything') // trueAPI
JWT
sign(payload, secret, options?)
sign(
payload: Record<string, unknown>,
secret: string,
options?: { expiresIn?: number }
): stringSigns payload with HMAC-SHA256 and returns a JWT string (header.payload.signature, all base64url-encoded).
| Parameter | Type | Description |
|-----------|------|-------------|
| payload | object | Data to embed; must be a plain object |
| secret | string | Non-empty signing secret |
| options.expiresIn | number | Expiry in seconds from now. Adds exp claim. |
Always adds an iat (issued-at) claim set to the current Unix timestamp.
Throws TypeError if secret is not a non-empty string or payload is not an object.
verify(token, secret)
verify(token: string, secret: string): Record<string, unknown>Verifies the token signature and expiry. Returns the decoded payload on success.
| Throws | When |
|--------|------|
| Error('Invalid token format') | Token is not a 3-part JWT string |
| Error('Invalid signature') | Signature does not match |
| Error('Token expired') | exp claim is in the past |
| Error('Invalid token payload') | Payload cannot be decoded |
decode(token)
decode(token: string): { header: object, payload: object }Decodes a JWT without verifying the signature. Useful for inspecting tokens without a secret.
Throws TypeError if token is not a string. Throws Error if the format is invalid.
API Keys
generateApiKey(options?)
generateApiKey(options?: { length?: number, prefix?: string }): stringGenerates a cryptographically secure API key using crypto.randomBytes.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| length | number | 32 | Number of random bytes; output is length * 2 hex characters |
| prefix | string | '' | Prefix prepended as {prefix}_{hex}. Omitted when empty. |
Each call returns a unique value. There is no way to reproduce a previous key.
hashApiKey(key, secret)
hashApiKey(key: string, secret: string): stringReturns an HMAC-SHA256 hex digest of key using secret. Use this to store API keys safely — store the hash, not the raw key.
Throws TypeError if either key or secret is an empty string.
validateApiKey(key, storedHash, secret)
validateApiKey(key: string, storedHash: string, secret: string): booleanRe-hashes key with secret and compares against storedHash using a timing-safe comparison (crypto.timingSafeEqual).
Returns false on any error (wrong types, empty strings, hash length mismatch). Never throws.
Permissions
hasPermission(userPermissions, required)
hasPermission(userPermissions: string[], required: string | string[]): booleanReturns true if the user holds all of the required permissions.
'*'inuserPermissionsgrants everything.- Returns
falseifuserPermissionsis not an array.
hasPermission(['posts:read', 'posts:write'], ['posts:read', 'posts:write']) // true
hasPermission(['posts:read'], 'posts:write') // false
hasPermission(['*'], 'any:permission') // truehasAnyPermission(userPermissions, required)
hasAnyPermission(userPermissions: string[], required: string | string[]): booleanReturns true if the user holds at least one of the required permissions.
'*'inuserPermissionsgrants everything.- Returns
falseifuserPermissionsis not an array.
hasAnyPermission(['posts:read'], ['posts:read', 'posts:write']) // true
hasAnyPermission(['comments:read'], 'posts:write') // falseError Handling
| Function | Throws | When |
|----------|--------|------|
| sign | TypeError | secret is empty or payload is not an object |
| verify | Error | Invalid format, wrong signature, expired, bad payload |
| decode | TypeError | token is not a string |
| decode | Error | Invalid JWT format |
| hashApiKey | TypeError | key or secret is empty |
| validateApiKey | never | Returns false on all error conditions |
| hasPermission | never | Returns false on bad input |
| hasAnyPermission | never | Returns false on bad input |
Examples
See examples/basic.js for a runnable demo:
node examples/basic.jsLicense
MIT
