@nitrotool/jwt
v1.0.5
Published
Lightweight JWT utilities for Nuxt/Nitro/UnJS environments **with built-in h3 helpers**.
Readme
@nitrotool/jwt
Lightweight JWT utilities for Nuxt/Nitro/UnJS environments with built-in h3 helpers.
- Built on
@tsndr/cloudflare-worker-jwt - Helpers that read
jwtSecretfrom your Nitro runtime config - Batteries included with h3 utilities to extract tokens from requests and enforce authentication
Learn more about JWT and how it works:
Installation
pnpm install @nitrotool/jwtnpm install @nitrotool/jwtRequired peer dependency:
h3(this package expectsh3to be present)
Nuxt setup
export default defineNuxtConfig({
modules: ['@nitrotool/jwt'],
//You can also
jwt: {
//default secret (only use this locally, and override it in prod)
secret: 'some-random-secret-yes-it-is-not-very-secure',
// Alternatively also available as NUXT_JWT_SECRET env var
},
});
Usage with Nuxt 3/4
This is available all places where auto-imported can be used on the server-side.
type MyClaims = { tenantId: string };
const token = await encodeJwt<MyClaims>({tenantId: '123', sub: '123'});
// Later…
const isValid = await verifyJwt(token);
const payload = await decodeJwt<MyClaims>(token);
// or
export default defineEventHandler(async (event) => {
const jwt = await requireJwt(event);
// you now have access to a required JWT token via Authorization bearer header.
})
Importing
Import from the main entry or subpaths:
// Node-only helpers
import {encodeJwtRaw, verifyJwtRaw, decodeJwtRaw} from '@nitrotool/jwt/core';
// h3-only helpers
import {extractApiToken, requireApiToken} from '@nitrotool/jwt/h3';Quick Start Nitro
1. Create plugin to load secret.
// plugins/0.jwt.ts
import { defineNitroPlugin, useRuntimeConfig } from 'nitropack/runtime';
import { configureJwtRuntime } from '@nitrotool/jwt';
export default defineNitroPlugin(() => {
configureJwtRuntime(() => useRuntimeConfig() as any);
});
2. Basic usage
import {encodeJwt, verifyJwt, decodeJwt} from '@nitrotool/jwt';
type MyClaims = { tenantId: string };
const token = await encodeJwt<MyClaims>({tenantId: '123', sub: '123'});
// Later…
const isValid = await verifyJwt(token);
const payload = await decodeJwt<MyClaims>(token); // { sub: '123', tenantId: '123', exp: ... }By default, non-Raw helpers read the secret from your runtime config:
useRuntimeConfig().jwtSecret
If you need to pass a secret explicitly, use the *Raw variants.
3. In a route handler
Extract API tokens and enforce authentication in request handlers:
Require a JWT token
import {defineEventHandler} from 'h3';
import {requireJwt} from '@nitrotool/jwt';
export default defineEventHandler(async (event) => {
const decodedJwt = await requireJwt(event)
})Extract a JWT token manually
import { defineEventHandler } from 'h3';
import { extractApiToken, requireApiToken, decodeJwt } from '@nitrotool/jwt';
export default defineEventHandler(async (event) => {
// Try to read token (Authorization: Bearer <token> or ?<queryKey>=<token>)
const token = extractApiToken(event, {queryKey: 'token'}); // queryKey defaults to 'token'
// Or strictly require it (throws UnauthenticatedError if missing)
const requiredToken = requireApiToken(event);
// Optionally decode/verify
const claims = await decodeJwt<{ userId: string }>(requiredToken);
return { ok: true, userId: claims.userId };
});Supported token locations:
- Authorization header:
Authorization: Bearer <token> - Query string:
?token=<token>
Configuration
When using non-Raw helpers, ensure a secret is available at runtime:
// nuxt.config.ts (Nuxt/Nitro runtime config)
export default defineNuxtConfig({
runtimeConfig: {
jwtSecret: 'some-random-secret-yes-it-is-not-very-secure',
},
});Examples
Sign with custom TTL:
import {encodeJwtRaw} from '@nitrotool/jwt';
const token = await encodeJwtRaw(
{userId: '123', role: 'admin'},
process.env.JWT_SECRET!,
60 * 10 // 10 minutes
);Decode without verifying signature (use only for non-sensitive scenarios):
import {decodeJwt} from '@nitrotool/jwt';
const payload = await decodeJwt<{ userId: string }>(token, {verify: false});Verify with an explicit secret:
import {verifyJwtRaw} from '@nitrotool/jwt';
const ok = await verifyJwtRaw(token, process.env.JWT_SECRET!);Errors
UnauthorizedError('Invalid JWT token.')is thrown when verification fails indecodeJwt/decodeJwtRaw.UnauthenticatedError()is thrown byrequireApiTokenwhen no token is present.
Security Notes
- Keep
jwtSecretstrong and private. - Prefer short TTLs and refresh flows.
- Only set
verify: falsefor non-sensitive, debug-like operations. - Rotate secrets periodically and invalidate old tokens if needed.
API Reference
All helpers are asynchronous.
JWT helpers
encodeJwtRaw<T>(payload, secret, ttl = 60): Promise<string>- Signs a token with the provided
secret. ttlis in seconds. Default:60.expis set automagically fromttl.
- Signs a token with the provided
encodeJwt<T>(payload, ttl = 60): Promise<string>- Same as
encodeJwtRaw, but usesuseRuntimeConfig().jwtSecret.
- Same as
verifyJwtRaw(token, secret): Promise<boolean>- Verifies signature and expiry using the provided
secret.
- Verifies signature and expiry using the provided
verifyJwt(token): Promise<boolean>- Same as
verifyJwtRaw, but usesuseRuntimeConfig().jwtSecret.
- Same as
decodeJwtRaw<T>(token, secret, { verify = true } = {}): Promise<T & Partial<JwtPayload>>- Decodes the token. When
verifyistrue, verifies signature and expiry. - Throws
UnauthorizedError('Invalid JWT token.')if verification fails. - Throws if
verifyistruebutsecretis empty.
- Decodes the token. When
decodeJwt<T>(token, { verify = true } = {}): Promise<T & Partial<JwtPayload>>- Same as
decodeJwtRaw, but usesuseRuntimeConfig().jwtSecret. - Throws
UnauthorizedError('Invalid JWT token.')if verification fails.
- Same as
Types:
ExtendableJwtPayload<T>lets you define custom claims merged with standard JWT claims.
h3 helpers (required)
extractBearerToken(event): string | undefined- Reads
Authorizationheader and returns the token withoutBearer.
- Reads
extractQueryToken(event, key = 'token'): string | undefined- Reads
tokenfrom the query string.
- Reads
extractApiToken(event): string | undefined- Returns the first non-empty token found by
extractBearerTokenorextractQueryToken.
- Returns the first non-empty token found by
requireApiToken(event): string- Same as
extractApiToken, but throwsUnauthenticatedErrorif missing.
- Same as
License
MIT
