Skip to content

Commit 2116c05

Browse files
Address copilot pass 5 on #4
The comment said the JWT lifetime is "capped at 5 minutes" but the code only used 5 minutes as a default — callers could pass arbitrarily large lifetimeSec and produce tokens the JSS verifier would later reject for exceeding MAX_LIFETIME (3600s). Now enforces the same 3600s cap at sign time so we don't mint tokens the server will refuse, and rejects non-numeric / non-positive input. Comment updated to describe the actual behavior (default 300s, enforced cap 3600s, matches server).
1 parent 614d512 commit 2116c05

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

lib/lws-cid-client.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,19 @@ export function buildEs256kVerificationMethod({ privKey, webId, controller, frag
106106

107107
// --- JWT signing -----------------------------------------------------
108108

109+
// Hard cap on token lifetime (exp − iat) — matches the JSS verifier's
110+
// MAX_LIFETIME so we never mint a token the server would reject for
111+
// being too long-lived, regardless of what callers pass.
112+
const MAX_LIFETIME_SEC = 3600;
113+
109114
/**
110115
* Sign an LWS10-CID JWT.
111116
*
112117
* Per the FPWD §4: sub === iss === client_id (all the WebID URI), aud
113-
* is the target server origin, exp/iat are required. Lifetime capped
114-
* at 5 minutes — the verifier rejects > 1h, but short tokens limit
115-
* the replay window if one leaks anyway.
118+
* is the target server origin, exp/iat are required. Default lifetime
119+
* is 5 minutes; callers can override but must stay ≤ 1 hour (the
120+
* server's MAX_LIFETIME) — anything longer is rejected here at sign
121+
* time so we don't produce tokens the verifier will refuse.
116122
*
117123
* @param {object} args
118124
* @param {Uint8Array|string} args.privKey
@@ -123,6 +129,15 @@ export function buildEs256kVerificationMethod({ privKey, webId, controller, frag
123129
* @returns {Promise<string>} compact JWS
124130
*/
125131
export async function signLwsCidJwt({ privKey, kid, webId, audience, lifetimeSec = 300 }) {
132+
if (typeof lifetimeSec !== 'number' || !Number.isFinite(lifetimeSec) || lifetimeSec <= 0) {
133+
throw new Error('lifetimeSec must be a positive number');
134+
}
135+
if (lifetimeSec > MAX_LIFETIME_SEC) {
136+
throw new Error(
137+
`lifetimeSec ${lifetimeSec} exceeds MAX_LIFETIME_SEC (${MAX_LIFETIME_SEC}) — ` +
138+
`the server would reject this token`,
139+
);
140+
}
126141
const priv = privKey instanceof Uint8Array ? privKey : validatePrivKey(privKey);
127142
const now = Math.floor(Date.now() / 1000);
128143
const header = { alg: 'ES256K', typ: 'JWT', kid };

0 commit comments

Comments
 (0)