A collection of low-level JWT (RFC 7519) utilities using the Web Crypto API. Supports:
-
JWS (JSON Web Signature, RFC 7515): sign and verify tokens using HMAC, RSA (RSASSA-PKCS1-v1_5 & RSA-PSS), and ECDSA algorithms.
-
JWE (JSON Web Encryption, RFC 7516): encrypt and decrypt data using various key management algorithms (AES Key Wrap, AES-GCM Key Wrap, RSA-OAEP, PBES2, ECDH-ES) and content encryption algorithms (AES-GCM, AES-CBC HMAC-SHA2).
-
JWK (JSON Web Key, RFC 7517): generate, import, export, wrap, and unwrap keys in JWK format or as
CryptoKeyobjects. -
Adapters for popular frameworks (PRs welcome for more!):
- H3 (Nuxt, Nitro):
useJWSSession(),useJWESession()
- H3 (Nuxt, Nitro):
Install the package:
# โจ Auto-detect (supports npm, yarn, pnpm, deno and bun)
npx nypm install unjwtImport:
ESM (Node.js, Bun, Deno)
import { jws, jwe, jwk } from "unjwt";
// JWS functions
import { sign, verify } from "unjwt/jws";
// JWE functions
import { encrypt, decrypt } from "unjwt/jwe";
// JWK functions
import {
generateKey,
generateJWK,
importJWKFromPEM,
exportJWKToPEM,
deriveKeyFromPassword,
deriveJWKFromPassword,
} from "unjwt/jwk";
// Utility functions
import {
isJWK,
isJWKSet,
isSymmetricJWK,
isAsymmetricJWK,
isPrivateJWK,
isPublicJWK,
} from "unjwt/utils";CDN (Deno, Bun and Browsers)
import { jws, jwe, jwk } from "https://esm.sh/unjwt";
// JWS functions
import { sign, verify } from "https://esm.sh/unjwt/jws";
// JWE functions
import { encrypt, decrypt } from "https://esm.sh/unjwt/jwe";
// JWK functions
import {
generateKey,
generateJWK,
importJWKFromPEM,
exportJWKToPEM,
deriveKeyFromPassword,
deriveJWKFromPassword,
} from "https://esm.sh/unjwt/jwk";
// Utility functions
import {
isJWK,
isJWKSet,
isSymmetricJWK,
isAsymmetricJWK,
isPrivateJWK,
isPublicJWK,
} from "https://esm.sh/unjwt/utils";JWS (JSON Web Signature, RFC 7515)
Functions to sign and verify data according to the JWS specification.
Creates a JWS token.
payload: The data to sign (string,Uint8Array, or a JSON-serializableobject).key: The signing key (CryptoKey,JWK, orUint8Arrayfor symmetric keys).options:alg: (Required) The JWS algorithm (e.g.,"HS256","RS256","ES256","PS256").protectedHeader: An object for additional JWS Protected Header parameters (e.g.,kid,typ,cty,crit,b64). Ifpayloadis an object andtypis not set, it defaults to"JWT". Theb64parameter (RFC7797 section-3) controls payload encoding (defaults totrue, meaning Base64URL encoded).expiresIn: Sets an expiration time in seconds (e.g.,3600for 1 hour). Ifiatis missing it will be set to the current time. Ifexpis missing it will be set toiat + expiresIn. This is only applied ifpayloadis a JWT.currentDate: The current date for computingexpiresInoption. Defaults tonew Date().
Returns a Promise<string> resolving to the JWS token in Compact Serialization format.
Example (HS256 with string secret):
import { sign } from "unjwt/jws";
const payload = { message: "My important data" }; // Object payload
const key = await generateKey("HS256", { toJWK: true }); // Generates a JWK_oct
const token = await sign(payload, key);
console.log(token);
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Example (RS256 with CryptoKey):
import { sign } from "unjwt/jws";
import { generateKey } from "unjwt/jwk";
const payload = { userId: 123, permissions: ["read"] };
const { privateKey } = await generateKey("RS256"); // Generates a CryptoKeyPair
const token = await sign(payload, privateKey, { alg: "RS256" });
console.log(token);
// eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...Verifies a JWS token.
jws: The JWS token string.key: The verification key (CryptoKey,JWK,JWKSet,Uint8Array, or aKeyLookupFunction). AKeyLookupFunctionhas the signature(header: JWSProtectedHeader, jws: string) => Promise<CryptoKey | JWK | JWKSet | Uint8Array> | CryptoKey | JWK | JWKSet | Uint8Array.options(optional):algorithms: An array of allowed JWSalgvalues. If not provided, thealgfrom the JWS header is used.validateJWT: Unless false, will parse payload as JWT and validate claims if applicable (typ includes "jwt", case insensitive). Defaultundefined.critical: An array of JWS header parameter names that the application understands and processes.
Returns a Promise<JWSVerifyResult<T>> which is an object { payload: T, protectedHeader: JWSProtectedHeader }.
The payload type T can be JWTClaims (object), string, or Uint8Array depending on the JWS content and headers.
Example (HS256):
import { verify } from "unjwt/jws";
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."; // From HS256 sign example
const secret = "supersecretkey";
const { payload, protectedHeader } = await verify(token, secret);
console.log(payload); // { message: "My important data" }
console.log(protectedHeader); // { alg: "HS256", typ: "JWT" }Example (RS256 with key lookup):
import { verify } from "unjwt/jws";
import { generateKey } from "unjwt/jwk";
const token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."; // From RS256 sign example
// Example: using a key lookup function
const { publicKey: rsaPublicKey } = await generateKey("RS256"); // For example purposes, assume publicKey is stored/fetched during lookup
const keyLookup = async (header) => {
if (header.alg === "RS256" /* && header.kid === 'expected-kid' */) {
return rsaPublicKey;
}
throw new Error("Unsupported algorithm or key not found");
};
const { payload } = await verify(token, keyLookup, { algorithms: ["RS256"] });
console.log(payload); // { userId: 123, permissions: ["read"] }JWE (JSON Web Encryption, RFC 7516)
Functions to encrypt and decrypt data according to the JWE specification.
Encrypts data to produce a JWE token.
payload: The data to encrypt (string,Uint8Array, or a JSON-serializableobject).key: The Key Encryption Key (KEK) or password (CryptoKey,JWK,string, orUint8Array).options:alg: (Required) The JWE Key Management algorithm (e.g.,"A128KW","RSA-OAEP-256","PBES2-HS256+A128KW","ECDH-ES+A128KW"), defaults depends on the key provided.enc: (Required) The JWE Content Encryption algorithm (e.g.,"A128GCM","A256CBC-HS512"), defaults depends on the key provided.protectedHeader: An object for JWE Protected Header parameters (e.g.,kid,typ,cty,crit,apu,apv,p2s,p2c). Ifpayloadis an object andtypis not set, it defaults to"JWT".cek: (Optional) Provide your own Content Encryption Key (CryptoKeyorUint8Array).contentEncryptionIV: (Optional) Provide your own Initialization Vector for content encryption (Uint8Array).- Other algorithm-specific options like
p2s,p2c(for PBES2),keyManagementIV,ecdhPartyUInfo,ecdhPartyVInfo.
Returns a Promise<string> resolving to the JWE token in Compact Serialization format.
Example (PBES2 password-based encryption):
import { encrypt } from "unjwt/jwe";
const plaintext = "Secret message for password protection";
const password = "myVeryStrongPassword123!";
// Fallback to PBES2-HS256+A128KW and A128GCM if no `alg` and `end` are provided
const jweToken = await encrypt(plaintext, password);
console.log(jweToken);
// JWE token string...Example (A128KW with A128GCM):
import { encrypt } from "unjwt/jwe";
import { generateKey } from "unjwt/jwk";
const payload = { data: "sensitive information" };
const kek = await generateKey("A128KW"); // AES Key Wrap key
const jweToken = await encrypt(payload, kek, {
alg: "A128KW",
enc: "A128GCM",
protectedHeader: { kid: "aes-key-1" },
});
console.log(jweToken);
// eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiYWVzLWtleS0xIn0...Decrypts a JWE token.
jwe: The JWE token string.key: The Key Decryption Key (KDK) or password (CryptoKey,JWK,string,Uint8Array, or aJWEKeyLookupFunction). AJWEKeyLookupFunctionhas the signature(header: JWEHeaderParameters) => Promise<CryptoKey | JWK | string | Uint8Array> | CryptoKey | JWK | string | Uint8Array.options(optional):algorithms: Array of allowed JWE Key Managementalgvalues.validateJWT: Unless false, will parse payload as JWT and validate claims if applicable (typ includes "jwt", case insensitive). Defaultundefined.encryptionAlgorithms: Array of allowed JWE Content Encryptionencvalues.critical: Array of JWE header parameter names that the application understands.unwrappedKeyAlgorithm: (ForunwrapKeyinternally) Algorithm details for the CEK after unwrapping.keyUsage: (ForunwrapKeyinternally) Intended usages for the unwrapped CEK.
Returns a Promise<JWEDecryptResult<T>> which is an object { payload: T, protectedHeader: JWEHeaderParameters, cek: Uint8Array, aad: Uint8Array }.
The payload type T can be JWTClaims (object) or string.
Example (PBES2 password-based decryption):
import { decrypt } from "unjwt/jwe";
// const jweToken = ...; // From PBES2 encrypt example
// const password = "myVeryStrongPassword123!";
const { payload } = await decrypt(jweToken, password);Example (A128KW with A128GCM):
import { decrypt } from "unjwt/jwe";
// const jweToken = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwia2lkIjoiYWVzLWtleS0xIn0...";
// const kek = ...; // The same AES Key Wrap key used for encryption
async function decryptData(jweToken: string, kek: CryptoKey) {
try {
const { payload, protectedHeader, cek } = await decrypt(jweToken, kek, {
algorithms: ["A128KW"],
encryptionAlgorithms: ["A128GCM"],
});
console.log("Decrypted Plaintext:", payload);
console.log("Protected Header:", protectedHeader);
// console.log("CEK (Content Encryption Key):", cek);
} catch (error) {
console.error("Decryption failed:", error);
}
}JWK (JSON Web Key, RFC 7517)
Utilities for working with JSON Web Keys.
Generates a cryptographic key.
alg: The JWA algorithm identifier for the key to be generated (e.g.,"HS256","RS256","ES256","A128KW","A128GCM","A128CBC-HS256").options(optional):toJWK: Iftrue, returns the key(s) in JWK format. Otherwise, returnsCryptoKey(s) orUint8Array(for composite keys like AES-CBC-HS*). Defaultfalse.extractable: Boolean, whether the generatedCryptoKeycan be exported. Defaulttrue.keyUsage: Array ofKeyUsagestrings. Defaults are algorithm-specific.modulusLength: For RSA keys (e.g.,2048,4096). Default2048.publicExponent: For RSA keys. Defaultnew Uint8Array([0x01, 0x00, 0x01]).
Returns a Promise resolving to CryptoKey, CryptoKeyPair, Uint8Array (for composite keys), JWK, or { privateKey: JWK, publicKey: JWK } depending on alg and options.toJWK.
Examples:
import { generateKey } from "unjwt/jwk";
// Generate an HS256 CryptoKey
const hmacKey = await generateKey("HS256");
console.log(hmacKey); // CryptoKey
// Generate an RS256 CryptoKeyPair
const rsaKeyPair = await generateKey("RS256", { modulusLength: 2048 });
console.log(rsaKeyPair.publicKey); // CryptoKey
console.log(rsaKeyPair.privateKey); // CryptoKey
// Generate an ES384 key pair as JWKs
const ecJwks = await generateKey("ES384", { toJWK: true });
console.log(ecJwks.publicKey); // JWK
console.log(ecJwks.privateKey); // JWK
// Generate a composite key for A128CBC-HS256 as Uint8Array
const aesCbcHsKeyBytes = await generateKey("A128CBC-HS256");
console.log(aesCbcHsKeyBytes); // Uint8Array (32 bytes: 16 for AES, 16 for HMAC)
// Generate an A256GCM key as a JWK
const aesGcmJwk = await generateKey("A256GCM", { toJWK: true });
console.log(aesGcmJwk); // JWKDerives a key from a password using PBKDF2 for PBES2 algorithms.
password: The password (stringorUint8Array).alg: The PBES2 algorithm (e.g.,"PBES2-HS256+A128KW").options:salt: The salt (Uint8Array, at least 8 octets).iterations: The iteration count (positive integer).toJWK: Iftrue, returns aJWK_oct. Otherwise,CryptoKey. Defaultfalse.extractable: Boolean forCryptoKey. DefaultfalseunlesstoJWKis true.keyUsage: ForCryptoKey. Default["wrapKey", "unwrapKey"].
Returns a Promise resolving to CryptoKey or JWK_oct.
Example:
import { deriveKeyFromPassword } from "unjwt/jwk";
import { randomBytes, textEncoder } from "unjwt/utils";
const password = "mySecretPassword";
const salt = randomBytes(16);
const iterations = 4096;
const derivedKey = await deriveKeyFromPassword(password, "PBES2-HS384+A192KW", {
salt,
iterations,
});
console.log(derivedKey); // CryptoKey for AES-KW (192-bit)
const derivedJwk = await deriveKeyFromPassword(password, "PBES2-HS512+A256KW", {
salt,
iterations,
toJWK: true,
});
console.log(derivedJwk); // JWK_oct { kty: "oct", k: "...", alg: "A256KW" }Imports a key from various formats. This is a flexible wrapper.
keyMaterial: The key to import. Can be:CryptoKey: Returned directly.Uint8Array: Returned directly (treated as raw symmetric key bytes).string: Encoded toUint8Arrayand returned.JWK_oct(symmetric JWK withkproperty): Thekvalue is Base64URL decoded and returned asUint8Array.- Other
JWKtypes (asymmetric): Imported into aCryptoKey.
alg(optional): The JWA algorithm string. Required when importing asymmetric JWKs (e.g., RSA, EC) to provide context forcrypto.subtle.importKey.
Returns a Promise resolving to CryptoKey or Uint8Array.
Examples:
import { importKey } from "unjwt/jwk";
import { textEncoder, base64UrlDecode } from "unjwt/utils";
// Import raw symmetric key bytes
const rawBytes = textEncoder.encode("a-32-byte-long-secret-key-123"); // 32 bytes for AES-256 or HS256
const symmetricKeyBytes = await importKey(rawBytes);
console.log(symmetricKeyBytes); // Uint8Array
// Import a symmetric JWK (kty: "oct")
const octJwk = {
kty: "oct",
k: "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr0", // Example key
};
const importedOctBytes = await importKey(octJwk); // Returns Uint8Array
console.log(importedOctBytes); // Uint8Array (decoded from k)
// Import an RSA Public Key JWK
const rsaPublicJwk = {
kty: "RSA",
n: "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3ok92YEnjsADC4Ue87zwRzH2J-TCwlcQrY3E9gGZJZL2g_2_5QjLhL0gR0xYj04_N4M",
e: "AQAB",
alg: "RS256",
kid: "rsa-pub-1",
};
const rsaPublicKey = await importKey(rsaPublicJwk, "RS256"); // 'alg' is crucial here
console.log(rsaPublicKey); // CryptoKeyExports a CryptoKey to JWK format.
key: TheCryptoKeyto export (must beextractable).jwk(optional): A partialJWKobject to merge with the exported properties (e.g., to addkid,use, or overridealg).
Returns a Promise<JWK>.
Example:
import { generateKey, exportKey } from "unjwt/jwk";
const { publicKey } = await generateKey("ES256"); // Generates an extractable CryptoKey
const jwk = await exportKey(publicKey, { kid: "ec-key-001", use: "sig" });
console.log(jwk);
// {
// kty: 'EC',
// crv: 'P-256',
// x: '...',
// y: '...',
// ext: true,
// key_ops: [ 'verify' ], // or as per generation
// kid: 'ec-key-001',
// use: 'sig'
// }Wraps a Content Encryption Key (CEK).
alg: The JWA key management algorithm (e.g.,"A128KW","RSA-OAEP").keyToWrap: The CEK to wrap (CryptoKeyorUint8Array).wrappingKey: The Key Encryption Key (KEK) (CryptoKey,JWK, or passwordstring/Uint8Arrayfor PBES2).options(optional): Algorithm-specific options (e.g.,p2s,p2cfor PBES2;ivfor AES-GCMKW).
Returns a Promise<WrapKeyResult> containing encryptedKey and other parameters like iv, tag, epk, p2s, p2c as needed by the algorithm.
Example (AES Key Wrap):
import { wrapKey, generateKey } from "unjwt/jwk";
import { randomBytes } from "unjwt/utils";
const cekToWrap = randomBytes(32); // e.g., a 256-bit AES key as Uint8Array
const kek = await generateKey("A128KW"); // 128-bit AES Key Wrap key
const { encryptedKey } = await wrapKey("A128KW", cekToWrap, kek);
console.log("Wrapped CEK:", encryptedKey); // Uint8ArrayUnwraps a Content Encryption Key (CEK).
alg: The JWA key management algorithm.wrappedKey: The encrypted CEK (Uint8Array).unwrappingKey: The Key Decryption Key (KDK).options(optional):returnAs: Iffalse, returnsUint8Array. Iftrue(default) or undefined, returnsCryptoKey.unwrappedKeyAlgorithm:AlgorithmIdentifierfor the imported CEK ifreturnAsistrue.keyUsage:KeyUsage[]for the imported CEK ifreturnAsistrue.extractable: Boolean for the imported CEK.- Other algorithm-specific options (e.g.,
p2s,p2c,iv,tag,epk).
Returns a Promise resolving to the unwrapped CEK as CryptoKey or Uint8Array.
Example (AES Key Unwrap):
import { unwrapKey, generateKey } from "unjwt/jwk";
// const encryptedKey = ...; // From wrapKey example
// const kdk = ...; // Same KEK used for wrapping
async function unwrapMyKey(encryptedKey: Uint8Array, kdk: CryptoKey) {
const unwrappedCekBytes = await unwrapKey("A128KW", encryptedKey, kdk, {
returnAs: false, // Get raw bytes
});
console.log("Unwrapped CEK (bytes):", unwrappedCekBytes); // Uint8Array
const unwrappedCekCryptoKey = await unwrapKey("A128KW", encryptedKey, kdk, {
returnAs: true, // Get CryptoKey
unwrappedKeyAlgorithm: { name: "AES-GCM", length: 256 }, // Specify CEK's intended alg
keyUsage: ["encrypt", "decrypt"],
});
console.log("Unwrapped CEK (CryptoKey):", unwrappedCekCryptoKey); // CryptoKey
}Imports a key from a PEM-encoded string and converts it to a JWK.
pem: The PEM-encoded string (including-----BEGIN ...-----and-----END ...-----markers).pemType: The type of PEM encoding:"pkcs8": For private keys in PKCS#8 format."spki": For public keys in SPKI format."x509": For X.509 certificates (extracts the public key).
alg: The JWA algorithm identifier (e.g.,"RS256","ES256"). This is crucial forcrypto.subtle.importKeyto understand the key's intended algorithm and for setting the'alg'field in the resulting JWK.importOptions(optional): Options for the underlyingcrypto.subtle.importKeycall:extractable: Boolean, whether the importedCryptoKeyshould be extractable. Defaults totrue.keyUsage: Array ofKeyUsagestrings for the importedCryptoKey.
jwkExtras(optional): An object containing additional properties to merge into the resulting JWK (e.g.,"kid","use").
Returns a Promise<JWK> resolving to the imported key as a JWK.
Example:
import { importJWKFromPEM } from "unjwt/jwk";
const rsaPublicJwk = await importJWKFromPEM(
provess.env.RSA_PEM_SPKI, // PEM string
"spki",
"RS256",
{ extractable: false },
{ kid: "my-rsa-key" }, // Additional properties to add to the JWK
);
console.log(rsaPublicJwk);
// {
// kty: 'RSA',
// alg: 'RS256',
// kid: 'my-rsa-key',
// n: '...',
// e: 'AQAB',
// ext: false,
// key_ops: [ 'verify' ]
// }Exports a JWK to a PEM-encoded string.
- jwk: The JWK to export.
- pemFormat: The desired PEM format:
- "pkcs8": For private keys in PKCS#8 format.
- "spki": For public keys in SPKI format.
- algForCryptoKeyImport (optional): If the JWK does not have an 'alg' property, this algorithm hint is required to correctly convert it to a CryptoKey first. This is only needed if the JWK lacks an alg property.
Returns a Promise<string> resolving to the PEM-encoded key string.
Example:
import { exportJWKToPEM } from "unjwt/jwk";
import { rsaJWK } from "./keys"; // Assuming you have JWKs in keys.ts
const rsaPrivatePem = await exportJWKToPEM(rsaJWK.private, "pkcs8");
console.log(rsaPrivatePem);
// -----BEGIN PRIVATE KEY-----
// MII...
// -----END PRIVATE KEY-----
const rsaPublicSpki = await exportJWKToPEM(
rsaJWK.public,
"spki",
"RS256", // this is required if `rsaJWK.public.alg` is undefined
);
console.log(rsaPublicSpki);
// -----BEGIN PUBLIC KEY-----
// MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQE...
// -----END PUBLIC KEY-----The h3v1 adapter bundles session helpers that store data inside signed or encrypted JWTs.
useJWESession(event, config)encrypts the session payload with the providedsecret(password string or private/symmetric JWK). Use this when session data must remain confidential. (cookie'shttpOnly: trueby default)useJWSSession(event, config)signs, but does not encrypt, the session payload withconfig.key. Use this when clients may read the session content but you still need tamper protection. (cookie'shttpOnly: falseby default)
Both helpers expose the same API: read session.id / session.data, call session.update() to patch values, and session.clear() to invalidate the cookie. When setting maxAge, exp claim is automatically managed and validated. They also support a number of hooks in the config for custom logic (e.g. logging, refreshing, etc).
import { defineEventHandler } from "h3";
import { useJWESession, useJWSSession, generateJWK } from "unjwt/adapters/h3v1";
const keys = await generateJWK("RS256");
export default defineEventHandler(async (event) => {
const privateSession = await useJWESession(event, {
name: "app-session",
secret: process.env.SESSION_SECRET!, // or symmetric or asymmetric keypair
});
await privateSession.update((data) => ({
visits: (data.visits ?? 0) + 1,
}));
const publicSession = await useJWSSession(event, {
name: "app-session-public",
key: keys, // you can directly pass symmetric or asymmetric keypairs
maxAge: 60 * 60, // seconds
});
return {
encryptedSession: privateSession.data,
signedSession: publicSession.data,
};
});The h3v2 adapter bundles session helpers that store data inside signed or encrypted JWTs.
useJWESession(event, config)encrypts the session payload with the providedsecret(password string or private/symmetric JWK). Use this when session data must remain confidential. (cookie'shttpOnly: trueby default)useJWSSession(event, config)signs, but does not encrypt, the session payload withconfig.key. Use this when clients may read the session content but you still need tamper protection. (cookie'shttpOnly: falseby default)
Both helpers expose the same API: read session.id / session.data, call session.update() to patch values, and session.clear() to invalidate the cookie. When setting maxAge, exp claim is automatically managed and validated. They also support a number of hooks in the config for custom logic (e.g. logging, refreshing, etc).
import { H3, HTTPError, serve } from "h3v2";
import {
type SessionConfigJWE,
type SessionConfigJWS,
useJWESession,
useJWSSession,
getJWESession,
updateJWSSession,
generateJWK,
} from "unjwt/adapters/h3v2";
const atJwk = await generateJWK("RS256");
const jweOptions = {
key: "refresh_token_secret",
name: "refresh_token",
} satisfies SessionConfigJWE;
const jwsOptions = {
key: atJwk,
name: "access_token",
maxAge: 15 * 60, // 15 minutes
hooks: {
async onExpire(event, _error, config) {
const refreshSession = await getJWESession(event, jweOptions);
if (!refreshSession.data.sub) {
// no valid refresh session, nothing to do
return;
}
console.log("Access token expired, refreshing...");
// refresh the access token
await updateJWSSession(event, config, {
sub: refreshSession.data.sub,
scope: refreshSession.data.scope,
});
},
},
} satisfies SessionConfigJWS;
const app = new H3();
app.post("/login", async (event) => {
const refreshSession = await useJWESession(event, jweOptions);
const accessSession = await useJWSSession(event, jwsOptions);
if (accessSession.data.sub) {
// user already logged in, return existing info
return {
accessToken: {
id: accessSession.id,
createdAt: accessSession.createdAt,
expiresAt: accessSession.expiresAt,
data: accessSession.data,
},
refreshSession: {
id: refreshSession.id,
createdAt: refreshSession.createdAt,
expiresAt: refreshSession.expiresAt,
data: refreshSession.data,
},
};
}
const data = (await event.req.json()) as {
username?: string;
password?: string;
};
if (!data.username || !data.password) {
throw new HTTPError("Username and password are required", { status: 400 });
}
// validate user credentials here
const claims = {
sub: data.username,
scope: ["read:profile"],
};
await accessSession.update(claims);
await refreshSession.update(claims);
return {
accessToken: {
id: accessSession.id,
createdAt: accessSession.createdAt,
expiresAt: accessSession.expiresAt,
data: accessSession.data,
},
refreshSession: {
id: refreshSession.id,
createdAt: refreshSession.createdAt,
expiresAt: refreshSession.expiresAt,
data: refreshSession.data,
},
};
});
serve(app);unjwt/utils exports several helpful functions:
base64UrlEncode(data: Uint8Array | string): stringbase64UrlDecode(str?: string, toString?: boolean): Uint8Array | string(Decodes to string by default, orUint8ArrayiftoStringisfalse)randomBytes(length: number): Uint8ArraytextEncoder: TextEncodertextDecoder: TextDecoder- Type guards:
isJWK(key),isCryptoKey(key),isCryptoKeyPair(keyPair)
local development
Originally developed by Johann Schopplich. Heavily inspired by Filip Skokan's work.
Published under the MIT license.
Made by community ๐
๐ค auto updated with automd