JSON Web Signature (RFC 7515) — sign/verify HS*/EdDSA tokens (JWT alternative).
Module jws | Source packages/front/fw/src/crypto/utils/jws.js | Deps bitArray, utf8, b64, hmac, sha256, sha512, ed25519 | Worker-safe yes
Compact header.payload.signature format (Base64url segments). Supported algorithms: HS256, HS512, EdDSA. (HS384 not supported — no sha384 dep in the factory.)
Resolve
const jws = runtime.resolve('jws');
// Returns: { sign, verify, signJwt, verifyJwt }
API
| Method | Signature | Returns |
|---|---|---|
sign(payload, alg, key, extraHeader?) |
(Uint8Array, 'HS256'|'HS512'|'EdDSA', Uint8Array, Object?) => string | false |
Compact JWS token |
verify(token, key, opts?) |
(string, Uint8Array, {expectedAlg?, expectedTyp?}) => {header, payload} | false |
Verified result or false |
signJwt(claims, alg, key) |
(Object, string, Uint8Array) => string | false |
Sign shortcut with typ:'JWT' |
verifyJwt(token, key, opts?) |
(string, Uint8Array, {expectedAlg?, expectedTyp?}) => {header, payload, claims} | false |
Verify + parse JSON claims |
verify / verifyJwt — options
| Option | Type | Description |
|---|---|---|
expectedAlg |
string | string[] |
Algorithm allowlist (anti-alg-confusion / downgrade) |
expectedTyp |
string |
Expected value of the typ field (anti-cross-protocol confusion) |
Examples
HS256 / JWT
const { jws } = fw.runtime.resolveAll(['jws']);
// Raw JWS (Uint8Array payload)
const payload = new TextEncoder().encode(JSON.stringify({ sub: '42' }));
const token = jws.sign(payload, 'HS256', secretKey);
const out = jws.verify(token, secretKey, { expectedAlg: 'HS256' });
// { header: {alg:'HS256', typ:'JWS'}, payload: Uint8Array }
// JWT shortcut (stringifies claims + typ:'JWT')
const jwt = jws.signJwt({ sub: '42', exp: 9999999999 }, 'HS256', secretKey);
const res = jws.verifyJwt(jwt, secretKey, { expectedAlg: 'HS256', expectedTyp: 'JWT' });
// { header, payload, claims: { sub: '42', exp: 9999999999 } }
EdDSA
const { jws, ed25519 } = fw.runtime.resolveAll(['jws', 'ed25519']);
const { secretKey, publicKey } = ed25519.keyPair(random.bytes(32));
const payload = new TextEncoder().encode(JSON.stringify({ sub: '42' }));
const token = jws.sign(payload, 'EdDSA', secretKey);
const out = jws.verify(token, publicKey, { expectedAlg: 'EdDSA' });
Worker Usage
const worker = fw.createWorker(
function ({ libs, args }) {
const payload = new TextEncoder().encode(JSON.stringify(args[0]));
self.postMessage(libs.jws.sign(payload, 'HS256', args[1]));
},
{ dependencies: ['jws'], args: [{ sub: '42' }, secretKey] }
);
Notes
verifywithexpectedAlg: always passexpectedAlgto prevent alg-confusion attacks (RFC 8725 §3.1) — e.g. an attacker flipping HS512→HS256 in the header.expectedTyp: use to prevent cross-protocol token reuse (e.g. a generic JWS token accepted as a JWT).- HS384 not supported — no
sha384dependency declared in the factory; warns if attempted. - alg='none' not accepted (RFC 8725 §3.1) — returns
false+console.warn('INVALID'). - HMAC verify constant-time: XOR-accumulated comparison, no early-exit.