@broberg/sso 0.21.0 → 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hono.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk2XMKZWC6_cjs = require('./chunk-2XMKZWC6.cjs');
3
+ var chunkQFUIWC2Q_cjs = require('./chunk-QFUIWC2Q.cjs');
4
4
  var hono = require('hono');
5
5
 
6
6
  var SESSION_KEY = "bidSession";
@@ -31,9 +31,9 @@ function safeReturnTo(raw, fallback) {
31
31
  return normalised;
32
32
  }
33
33
  function ssoRoutes(options = {}) {
34
- const baseConfig = options.config ?? chunk2XMKZWC6_cjs.loadSsoConfig();
34
+ const baseConfig = options.config ?? chunkQFUIWC2Q_cjs.loadSsoConfig();
35
35
  const config = options.clientAuth ? { ...baseConfig, clientAuth: options.clientAuth } : baseConfig;
36
- const client = options.client ?? chunk2XMKZWC6_cjs.createSsoClient(config);
36
+ const client = options.client ?? chunkQFUIWC2Q_cjs.createSsoClient(config);
37
37
  const loginPath = options.loginPath ?? "/auth";
38
38
  const defaultReturnTo = options.defaultReturnTo ?? "/";
39
39
  const txCookie = `${config.cookieName}_tx`;
@@ -47,7 +47,7 @@ function ssoRoutes(options = {}) {
47
47
  const callbackErrors = options.callbackErrors ?? "single";
48
48
  const onCallbackRefused = options.onCallbackRefused ?? ((cause) => console.warn(`[@broberg/sso] /callback refused: ${cause}`));
49
49
  async function liveSession(c) {
50
- const session = await chunk2XMKZWC6_cjs.verifySession(chunk2XMKZWC6_cjs.readCookie(c.req.header("cookie"), config.cookieName), config.cookieSecret);
50
+ const session = await chunkQFUIWC2Q_cjs.verifySession(chunkQFUIWC2Q_cjs.readCookie(c.req.header("cookie"), config.cookieName), config.cookieSecret);
51
51
  if (!session || !backchannel) return session;
52
52
  try {
53
53
  const before = await backchannel.store.revokedBefore(session.sub);
@@ -73,7 +73,7 @@ function ssoRoutes(options = {}) {
73
73
  try {
74
74
  verified = await client.verifyLogoutToken(token);
75
75
  } catch (e) {
76
- const msg = e instanceof chunk2XMKZWC6_cjs.SsoError ? e.message : "logout_token could not be verified";
76
+ const msg = e instanceof chunkQFUIWC2Q_cjs.SsoError ? e.message : "logout_token could not be verified";
77
77
  return c.json({ error: "invalid_request", error_description: msg }, 400);
78
78
  }
79
79
  try {
@@ -102,7 +102,7 @@ function ssoRoutes(options = {}) {
102
102
  // The signed stamp carries the SERVER's window; the cookie carries the
103
103
  // longer browser one, so an expired transaction still reaches us and can
104
104
  // be named instead of vanishing.
105
- chunk2XMKZWC6_cjs.cookieHeader(txCookie, await chunk2XMKZWC6_cjs.signValue(tx, config.cookieSecret, { maxAgeSeconds: TRANSACTION_MAX_AGE }), {
105
+ chunkQFUIWC2Q_cjs.cookieHeader(txCookie, await chunkQFUIWC2Q_cjs.signValue(tx, config.cookieSecret, { maxAgeSeconds: TRANSACTION_MAX_AGE }), {
106
106
  maxAge: TRANSACTION_COOKIE_MAX_AGE,
107
107
  secure: isSecure(c)
108
108
  })
@@ -111,7 +111,7 @@ function ssoRoutes(options = {}) {
111
111
  });
112
112
  app.get("/callback", async (c) => {
113
113
  const parsed = await parseTransaction(
114
- chunk2XMKZWC6_cjs.readCookie(c.req.header("cookie"), txCookie),
114
+ chunkQFUIWC2Q_cjs.readCookie(c.req.header("cookie"), txCookie),
115
115
  config.cookieSecret
116
116
  );
117
117
  if (!parsed.ok) {
@@ -143,7 +143,7 @@ function ssoRoutes(options = {}) {
143
143
  message: "This login could not be completed. Begin again from the login page."
144
144
  } : failures[parsed.reason];
145
145
  const { status, ...body } = shown;
146
- c.header("Set-Cookie", chunk2XMKZWC6_cjs.cookieHeader(txCookie, "", { maxAge: 0, secure: isSecure(c) }));
146
+ c.header("Set-Cookie", chunkQFUIWC2Q_cjs.cookieHeader(txCookie, "", { maxAge: 0, secure: isSecure(c) }));
147
147
  return c.json(body, status);
148
148
  }
149
149
  const result = await client.completeLogin({
@@ -156,12 +156,12 @@ function ssoRoutes(options = {}) {
156
156
  const exp = nowS + config.sessionMaxAge;
157
157
  let sid;
158
158
  if (tokenStore && result.accessToken) {
159
- sid = chunk2XMKZWC6_cjs.newSid();
159
+ sid = chunkQFUIWC2Q_cjs.newSid();
160
160
  await tokenStore.set(sid, {
161
161
  sub: result.claims.sub,
162
162
  accessToken: result.accessToken,
163
163
  ...result.refreshToken ? { refreshToken: result.refreshToken } : {},
164
- expiresAt: chunk2XMKZWC6_cjs.expiresAtFrom(result.expiresIn, result.accessToken, nowS)
164
+ expiresAt: chunkQFUIWC2Q_cjs.expiresAtFrom(result.expiresIn, result.accessToken, nowS)
165
165
  });
166
166
  }
167
167
  const session = {
@@ -177,14 +177,14 @@ function ssoRoutes(options = {}) {
177
177
  };
178
178
  c.header(
179
179
  "Set-Cookie",
180
- chunk2XMKZWC6_cjs.cookieHeader(config.cookieName, await chunk2XMKZWC6_cjs.signSession(session, config.cookieSecret), {
180
+ chunkQFUIWC2Q_cjs.cookieHeader(config.cookieName, await chunkQFUIWC2Q_cjs.signSession(session, config.cookieSecret), {
181
181
  maxAge: config.sessionMaxAge,
182
182
  secure: isSecure(c)
183
183
  })
184
184
  );
185
185
  c.header(
186
186
  "Set-Cookie",
187
- chunk2XMKZWC6_cjs.cookieHeader(idTokenCookie, await chunk2XMKZWC6_cjs.signValue(result.idToken, config.cookieSecret), {
187
+ chunkQFUIWC2Q_cjs.cookieHeader(idTokenCookie, await chunkQFUIWC2Q_cjs.signValue(result.idToken, config.cookieSecret), {
188
188
  maxAge: config.sessionMaxAge,
189
189
  secure: isSecure(c)
190
190
  }),
@@ -192,27 +192,27 @@ function ssoRoutes(options = {}) {
192
192
  );
193
193
  c.header(
194
194
  "Set-Cookie",
195
- chunk2XMKZWC6_cjs.cookieHeader(txCookie, "", { maxAge: 0, secure: isSecure(c) }),
195
+ chunkQFUIWC2Q_cjs.cookieHeader(txCookie, "", { maxAge: 0, secure: isSecure(c) }),
196
196
  { append: true }
197
197
  );
198
198
  return c.redirect(parsed.tx.returnTo, 302);
199
199
  });
200
200
  app.get("/logout", async (c) => {
201
- const idTokenHint = await chunk2XMKZWC6_cjs.verifyValue(
202
- chunk2XMKZWC6_cjs.readCookie(c.req.header("cookie"), idTokenCookie),
201
+ const idTokenHint = await chunkQFUIWC2Q_cjs.verifyValue(
202
+ chunkQFUIWC2Q_cjs.readCookie(c.req.header("cookie"), idTokenCookie),
203
203
  config.cookieSecret
204
204
  );
205
205
  if (tokenStore) {
206
- const leaving = await chunk2XMKZWC6_cjs.verifySession(chunk2XMKZWC6_cjs.readCookie(c.req.header("cookie"), config.cookieName), config.cookieSecret);
206
+ const leaving = await chunkQFUIWC2Q_cjs.verifySession(chunkQFUIWC2Q_cjs.readCookie(c.req.header("cookie"), config.cookieName), config.cookieSecret);
207
207
  if (leaving?.sid) await tokenStore.delete(leaving.sid);
208
208
  }
209
209
  c.header(
210
210
  "Set-Cookie",
211
- chunk2XMKZWC6_cjs.cookieHeader(config.cookieName, "", { maxAge: 0, secure: isSecure(c) })
211
+ chunkQFUIWC2Q_cjs.cookieHeader(config.cookieName, "", { maxAge: 0, secure: isSecure(c) })
212
212
  );
213
213
  c.header(
214
214
  "Set-Cookie",
215
- chunk2XMKZWC6_cjs.cookieHeader(idTokenCookie, "", { maxAge: 0, secure: isSecure(c) }),
215
+ chunkQFUIWC2Q_cjs.cookieHeader(idTokenCookie, "", { maxAge: 0, secure: isSecure(c) }),
216
216
  { append: true }
217
217
  );
218
218
  if ((options.logout ?? "app") === "app") {
@@ -239,23 +239,23 @@ function ssoRoutes(options = {}) {
239
239
  const refreshing = /* @__PURE__ */ new Map();
240
240
  async function getAccessToken(c) {
241
241
  if (!tokenStore) {
242
- throw new chunk2XMKZWC6_cjs.SsoError("getAccessToken needs ssoRoutes({ tokenStore }) \u2014 without one the login's tokens are not kept.");
242
+ throw new chunkQFUIWC2Q_cjs.SsoError("getAccessToken needs ssoRoutes({ tokenStore }) \u2014 without one the login's tokens are not kept.");
243
243
  }
244
- const raw = await chunk2XMKZWC6_cjs.verifySession(chunk2XMKZWC6_cjs.readCookie(c.req.header("cookie"), config.cookieName), config.cookieSecret);
244
+ const raw = await chunkQFUIWC2Q_cjs.verifySession(chunkQFUIWC2Q_cjs.readCookie(c.req.header("cookie"), config.cookieName), config.cookieSecret);
245
245
  const live = await liveSession(c);
246
246
  if (!live) {
247
247
  if (raw?.sid) await tokenStore.delete(raw.sid);
248
- throw new chunk2XMKZWC6_cjs.SsoReauthError("no live session \u2014 log in again.", "no_session");
248
+ throw new chunkQFUIWC2Q_cjs.SsoReauthError("no live session \u2014 log in again.", "no_session");
249
249
  }
250
250
  const sid = live.sid;
251
- if (!sid) throw new chunk2XMKZWC6_cjs.SsoReauthError("this session has no stored tokens (it began before tokenStore was configured) \u2014 log in again.", "no_tokens");
251
+ if (!sid) throw new chunkQFUIWC2Q_cjs.SsoReauthError("this session has no stored tokens (it began before tokenStore was configured) \u2014 log in again.", "no_tokens");
252
252
  const tokens = await tokenStore.get(sid);
253
- if (!tokens) throw new chunk2XMKZWC6_cjs.SsoReauthError("no tokens stored for this session \u2014 log in again.", "no_tokens");
253
+ if (!tokens) throw new chunkQFUIWC2Q_cjs.SsoReauthError("no tokens stored for this session \u2014 log in again.", "no_tokens");
254
254
  const now = Math.floor(Date.now() / 1e3);
255
255
  if (tokens.expiresAt - 30 > now) return tokens.accessToken;
256
256
  if (!tokens.refreshToken) {
257
257
  await tokenStore.delete(sid);
258
- throw new chunk2XMKZWC6_cjs.SsoReauthError("the access token has expired and there is no refresh token \u2014 log in again.", "expired");
258
+ throw new chunkQFUIWC2Q_cjs.SsoReauthError("the access token has expired and there is no refresh token \u2014 log in again.", "expired");
259
259
  }
260
260
  const inFlight = refreshing.get(sid);
261
261
  if (inFlight) return inFlight;
@@ -265,14 +265,14 @@ function ssoRoutes(options = {}) {
265
265
  next = await client.refreshTokens(tokens.refreshToken);
266
266
  } catch (e) {
267
267
  await tokenStore.delete(sid);
268
- throw new chunk2XMKZWC6_cjs.SsoReauthError(e instanceof chunk2XMKZWC6_cjs.SsoError ? e.message : "token refresh failed", "refresh_failed");
268
+ throw new chunkQFUIWC2Q_cjs.SsoReauthError(e instanceof chunkQFUIWC2Q_cjs.SsoError ? e.message : "token refresh failed", "refresh_failed");
269
269
  }
270
270
  await tokenStore.set(sid, {
271
271
  sub: tokens.sub,
272
272
  accessToken: next.accessToken,
273
273
  // Rotation: use the new one if BID issued one, else keep the old.
274
274
  ...next.refreshToken ?? tokens.refreshToken ? { refreshToken: next.refreshToken ?? tokens.refreshToken } : {},
275
- expiresAt: chunk2XMKZWC6_cjs.expiresAtFrom(next.expiresIn, next.accessToken, Math.floor(Date.now() / 1e3))
275
+ expiresAt: chunkQFUIWC2Q_cjs.expiresAtFrom(next.expiresIn, next.accessToken, Math.floor(Date.now() / 1e3))
276
276
  });
277
277
  return next.accessToken;
278
278
  })();
@@ -296,7 +296,7 @@ function ssoRoutes(options = {}) {
296
296
  if (left <= 0) return;
297
297
  c.header(
298
298
  "Set-Cookie",
299
- chunk2XMKZWC6_cjs.cookieHeader(config.cookieName, await chunk2XMKZWC6_cjs.signSession(next, config.cookieSecret), { maxAge: left, secure: isSecure(c) }),
299
+ chunkQFUIWC2Q_cjs.cookieHeader(config.cookieName, await chunkQFUIWC2Q_cjs.signSession(next, config.cookieSecret), { maxAge: left, secure: isSecure(c) }),
300
300
  { append: true }
301
301
  );
302
302
  }
@@ -304,9 +304,9 @@ function ssoRoutes(options = {}) {
304
304
  }
305
305
  async function parseTransaction(raw, secret) {
306
306
  if (raw === void 0) return { ok: false, reason: "absent" };
307
- const signed = await chunk2XMKZWC6_cjs.verifyValue(raw, secret);
307
+ const signed = await chunkQFUIWC2Q_cjs.verifyValue(raw, secret);
308
308
  if (signed === null) return { ok: false, reason: "unreadable" };
309
- const fresh = await chunk2XMKZWC6_cjs.verifyValue(raw, secret, { maxAgeSeconds: TRANSACTION_MAX_AGE });
309
+ const fresh = await chunkQFUIWC2Q_cjs.verifyValue(raw, secret, { maxAgeSeconds: TRANSACTION_MAX_AGE });
310
310
  if (fresh === null) return { ok: false, reason: "expired" };
311
311
  try {
312
312
  const tx = JSON.parse(fresh);
@@ -376,16 +376,16 @@ function accountRoutes(sso) {
376
376
  });
377
377
  app.post("/profile/avatar", async (c) => {
378
378
  const token = await sso.getAccessToken(c);
379
- const type = chunk2XMKZWC6_cjs.mediaType(c.req.header("content-type"));
380
- if (!chunk2XMKZWC6_cjs.AVATAR_TYPES.includes(type)) {
381
- return c.json({ error: "unsupported_type", accepted: chunk2XMKZWC6_cjs.AVATAR_TYPES }, 415);
379
+ const type = chunkQFUIWC2Q_cjs.mediaType(c.req.header("content-type"));
380
+ if (!chunkQFUIWC2Q_cjs.AVATAR_TYPES.includes(type)) {
381
+ return c.json({ error: "unsupported_type", accepted: chunkQFUIWC2Q_cjs.AVATAR_TYPES }, 415);
382
382
  }
383
383
  const declared = Number(c.req.header("content-length"));
384
- if (Number.isFinite(declared) && declared > chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES) {
385
- return c.json({ error: "too_large", max_bytes: chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES }, 413);
384
+ if (Number.isFinite(declared) && declared > chunkQFUIWC2Q_cjs.MAX_AVATAR_BYTES) {
385
+ return c.json({ error: "too_large", max_bytes: chunkQFUIWC2Q_cjs.MAX_AVATAR_BYTES }, 413);
386
386
  }
387
- const bytes = await readCapped(c, chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES);
388
- if (!bytes) return c.json({ error: "too_large", max_bytes: chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES }, 413);
387
+ const bytes = await readCapped(c, chunkQFUIWC2Q_cjs.MAX_AVATAR_BYTES);
388
+ if (!bytes) return c.json({ error: "too_large", max_bytes: chunkQFUIWC2Q_cjs.MAX_AVATAR_BYTES }, 413);
389
389
  return answer(c, await client.uploadAvatar(token, bytes, type));
390
390
  });
391
391
  app.post("/profile/avatar/remove", async (c) => answer(c, await client.removeAvatar(await sso.getAccessToken(c))));
@@ -398,7 +398,7 @@ function accountRoutes(sso) {
398
398
  case "SsoInsufficientScopeError":
399
399
  return c.json({ error: "insufficient_scope", scope: e.scope }, 403);
400
400
  case "SsoAvatarRejectedError":
401
- return e.reason === "too_large" ? c.json({ error: "too_large", max_bytes: chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES }, 413) : c.json({ error: "unsupported_type", accepted: chunk2XMKZWC6_cjs.AVATAR_TYPES }, 415);
401
+ return e.reason === "too_large" ? c.json({ error: "too_large", max_bytes: chunkQFUIWC2Q_cjs.MAX_AVATAR_BYTES }, 413) : c.json({ error: "unsupported_type", accepted: chunkQFUIWC2Q_cjs.AVATAR_TYPES }, 415);
402
402
  case "SsoAppApiError": {
403
403
  if (e.status === 401) return c.json({ error: "reauth" }, 401);
404
404
  if (typeof e.status === "number" && e.status >= 400 && e.status < 500) {
package/dist/hono.js CHANGED
@@ -1,4 +1,4 @@
1
- import { loadSsoConfig, createSsoClient, SsoError, cookieHeader, signValue, readCookie, newSid, expiresAtFrom, signSession, verifyValue, verifySession, mediaType, AVATAR_TYPES, MAX_AVATAR_BYTES, SsoReauthError } from './chunk-UDUPP35Z.js';
1
+ import { loadSsoConfig, createSsoClient, SsoError, cookieHeader, signValue, readCookie, newSid, expiresAtFrom, signSession, verifyValue, verifySession, mediaType, AVATAR_TYPES, MAX_AVATAR_BYTES, SsoReauthError } from './chunk-NIYOPNRE.js';
2
2
  import { Hono } from 'hono';
3
3
 
4
4
  var SESSION_KEY = "bidSession";
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk2XMKZWC6_cjs = require('./chunk-2XMKZWC6.cjs');
3
+ var chunkQFUIWC2Q_cjs = require('./chunk-QFUIWC2Q.cjs');
4
4
  var jose = require('jose');
5
5
 
6
6
  var PRINCIPAL_TYPES = ["human", "service", "agent", "user"];
@@ -17,11 +17,11 @@ function createTicketVerifier(options) {
17
17
  dpopIatWindowSec = 60,
18
18
  now = () => Date.now()
19
19
  } = options;
20
- const replayStore = options.replayStore ?? chunk2XMKZWC6_cjs.createMemoryReplayStore(now);
21
- if (!issuer) throw new chunk2XMKZWC6_cjs.SsoError("createTicketVerifier needs an issuer");
22
- if (!audience) throw new chunk2XMKZWC6_cjs.SsoError("createTicketVerifier needs this receiver's audience");
20
+ const replayStore = options.replayStore ?? chunkQFUIWC2Q_cjs.createMemoryReplayStore(now);
21
+ if (!issuer) throw new chunkQFUIWC2Q_cjs.SsoError("createTicketVerifier needs an issuer");
22
+ if (!audience) throw new chunkQFUIWC2Q_cjs.SsoError("createTicketVerifier needs this receiver's audience");
23
23
  let cachePromise = null;
24
- const cacheFor = (jwksUri) => chunk2XMKZWC6_cjs.createJwksCache({
24
+ const cacheFor = (jwksUri) => chunkQFUIWC2Q_cjs.createJwksCache({
25
25
  jwksUri,
26
26
  fetchImpl,
27
27
  ...options.warmUp ? { warmUp: true } : {},
@@ -37,12 +37,12 @@ function createTicketVerifier(options) {
37
37
  if (!res.ok) throw new Error(`answered ${res.status}`);
38
38
  doc = await res.json();
39
39
  } catch (cause) {
40
- throw new chunk2XMKZWC6_cjs.JwksUnavailableError(`${url}: ${cause instanceof Error ? cause.message : String(cause)}`);
40
+ throw new chunkQFUIWC2Q_cjs.JwksUnavailableError(`${url}: ${cause instanceof Error ? cause.message : String(cause)}`);
41
41
  }
42
42
  if (doc.issuer !== issuer) {
43
- throw new chunk2XMKZWC6_cjs.SsoError(`issuer is ${issuer} but ${url} says ${doc.issuer} \u2014 they must match exactly`);
43
+ throw new chunkQFUIWC2Q_cjs.SsoError(`issuer is ${issuer} but ${url} says ${doc.issuer} \u2014 they must match exactly`);
44
44
  }
45
- if (!doc.jwks_uri) throw new chunk2XMKZWC6_cjs.SsoError(`${url} names no jwks_uri`);
45
+ if (!doc.jwks_uri) throw new chunkQFUIWC2Q_cjs.SsoError(`${url} names no jwks_uri`);
46
46
  return cacheFor(doc.jwks_uri);
47
47
  })().catch((err) => {
48
48
  cachePromise = null;
@@ -58,52 +58,52 @@ function createTicketVerifier(options) {
58
58
  try {
59
59
  header = jose.decodeProtectedHeader(token);
60
60
  } catch {
61
- throw new chunk2XMKZWC6_cjs.SsoError("ticket is not a JWS");
61
+ throw new chunkQFUIWC2Q_cjs.SsoError("ticket is not a JWS");
62
62
  }
63
- if (!header.kid) throw new chunk2XMKZWC6_cjs.SsoError("ticket has no kid \u2014 cannot pick a signing key");
64
- if (header.typ === "logout+jwt") throw new chunk2XMKZWC6_cjs.SsoError("a logout token is not a ticket");
63
+ if (!header.kid) throw new chunkQFUIWC2Q_cjs.SsoError("ticket has no kid \u2014 cannot pick a signing key");
64
+ if (header.typ === "logout+jwt") throw new chunkQFUIWC2Q_cjs.SsoError("a logout token is not a ticket");
65
65
  const cache = await keys();
66
66
  let payload;
67
67
  try {
68
68
  ({ payload } = await jose.jwtVerify(token, async () => cache.getKey(header.kid, header.alg ?? "EdDSA"), {
69
69
  issuer,
70
70
  audience,
71
- algorithms: chunk2XMKZWC6_cjs.ALLOWED_ALGS,
71
+ algorithms: chunkQFUIWC2Q_cjs.ALLOWED_ALGS,
72
72
  clockTolerance: clockToleranceSec,
73
73
  requiredClaims: ["exp", "iat", "jti", "sub"]
74
74
  }));
75
75
  } catch (e) {
76
- if (e instanceof chunk2XMKZWC6_cjs.JwksUnavailableError) throw e;
77
- throw new chunk2XMKZWC6_cjs.SsoError(`ticket rejected: ${e instanceof Error ? e.message : String(e)}`);
76
+ if (e instanceof chunkQFUIWC2Q_cjs.JwksUnavailableError) throw e;
77
+ throw new chunkQFUIWC2Q_cjs.SsoError(`ticket rejected: ${e instanceof Error ? e.message : String(e)}`);
78
78
  }
79
- if ("events" in payload) throw new chunk2XMKZWC6_cjs.SsoError("a logout token is not a ticket");
80
- if ("nonce" in payload) throw new chunk2XMKZWC6_cjs.SsoError("an ID token is not a ticket");
79
+ if ("events" in payload) throw new chunkQFUIWC2Q_cjs.SsoError("a logout token is not a ticket");
80
+ if ("nonce" in payload) throw new chunkQFUIWC2Q_cjs.SsoError("an ID token is not a ticket");
81
81
  const type = payload.principal_type;
82
82
  if (typeof type !== "string" || !PRINCIPAL_TYPES.includes(type)) {
83
- throw new chunk2XMKZWC6_cjs.SsoError(`ticket has no valid principal_type (got ${JSON.stringify(type)})`);
83
+ throw new chunkQFUIWC2Q_cjs.SsoError(`ticket has no valid principal_type (got ${JSON.stringify(type)})`);
84
84
  }
85
85
  const lifetime = payload.exp - payload.iat;
86
86
  if (lifetime > maxLifetimeSec) {
87
- throw new chunk2XMKZWC6_cjs.SsoError(`ticket claims a ${lifetime}s lifetime; at most ${maxLifetimeSec}s is accepted`);
87
+ throw new chunkQFUIWC2Q_cjs.SsoError(`ticket claims a ${lifetime}s lifetime; at most ${maxLifetimeSec}s is accepted`);
88
88
  }
89
- if (typeof payload.sub !== "string" || payload.sub === "") throw new chunk2XMKZWC6_cjs.SsoError("ticket has no sub");
89
+ if (typeof payload.sub !== "string" || payload.sub === "") throw new chunkQFUIWC2Q_cjs.SsoError("ticket has no sub");
90
90
  const scopes = typeof payload.scope === "string" ? payload.scope.split(" ").filter(Boolean) : [];
91
91
  const required = opts.scope === void 0 ? [] : Array.isArray(opts.scope) ? opts.scope : [opts.scope];
92
92
  const missing = required.filter((s) => !scopes.includes(s));
93
- if (missing.length) throw new chunk2XMKZWC6_cjs.SsoError(`ticket lacks scope ${missing.join(", ")}`);
93
+ if (missing.length) throw new chunkQFUIWC2Q_cjs.SsoError(`ticket lacks scope ${missing.join(", ")}`);
94
94
  const ver = payload.ver === void 0 ? 0 : payload.ver;
95
95
  if (typeof ver !== "number" || !Number.isInteger(ver) || ver < 0) {
96
- throw new chunk2XMKZWC6_cjs.SsoError(`ticket has an invalid ver (got ${JSON.stringify(payload.ver)})`);
96
+ throw new chunkQFUIWC2Q_cjs.SsoError(`ticket has an invalid ver (got ${JSON.stringify(payload.ver)})`);
97
97
  }
98
98
  if (ver > TICKET_FORMAT_VERSION) {
99
- throw new chunk2XMKZWC6_cjs.SsoError(`ticket format version ${ver} is newer than this @broberg/sso understands (${TICKET_FORMAT_VERSION}) \u2014 upgrade @broberg/sso`);
99
+ throw new chunkQFUIWC2Q_cjs.SsoError(`ticket format version ${ver} is newer than this @broberg/sso understands (${TICKET_FORMAT_VERSION}) \u2014 upgrade @broberg/sso`);
100
100
  }
101
101
  const act = payload.act === void 0 ? null : readActor(payload.act, 1);
102
102
  const cnfRaw = payload.cnf;
103
103
  const cnf = cnfRaw && typeof cnfRaw.jkt === "string" && cnfRaw.jkt ? { jkt: cnfRaw.jkt } : null;
104
104
  if (cnf) {
105
- if (!opts.dpop?.proof) throw new chunk2XMKZWC6_cjs.SsoError("ticket is DPoP-bound (cnf.jkt) but no DPoP proof was presented");
106
- await chunk2XMKZWC6_cjs.verifyDpopProof(opts.dpop.proof, {
105
+ if (!opts.dpop?.proof) throw new chunkQFUIWC2Q_cjs.SsoError("ticket is DPoP-bound (cnf.jkt) but no DPoP proof was presented");
106
+ await chunkQFUIWC2Q_cjs.verifyDpopProof(opts.dpop.proof, {
107
107
  method: opts.dpop.method,
108
108
  url: opts.dpop.url,
109
109
  ticket: token,
@@ -113,11 +113,11 @@ function createTicketVerifier(options) {
113
113
  now
114
114
  });
115
115
  } else if (requireDpop) {
116
- throw new chunk2XMKZWC6_cjs.SsoError(cnfRaw !== void 0 ? "ticket has a cnf without a string jkt \u2014 DPoP is required here" : "this receiver requires DPoP; the ticket is not bound (no cnf.jkt)");
116
+ throw new chunkQFUIWC2Q_cjs.SsoError(cnfRaw !== void 0 ? "ticket has a cnf without a string jkt \u2014 DPoP is required here" : "this receiver requires DPoP; the ticket is not bound (no cnf.jkt)");
117
117
  }
118
118
  const named = (v) => typeof v === "string" && v ? v : null;
119
119
  const clientId = type === "user" ? named(payload.client_id) ?? named(payload.azp) : named(payload.client_id) ?? payload.sub;
120
- if (clientId === null) throw new chunk2XMKZWC6_cjs.SsoError("a user ticket names no app (no client_id or azp)");
120
+ if (clientId === null) throw new chunkQFUIWC2Q_cjs.SsoError("a user ticket names no app (no client_id or azp)");
121
121
  return {
122
122
  principal: payload.sub,
123
123
  type,
@@ -134,181 +134,181 @@ function createTicketVerifier(options) {
134
134
  };
135
135
  }
136
136
  function readActor(raw, depth) {
137
- if (depth > MAX_ACT_DEPTH) throw new chunk2XMKZWC6_cjs.SsoError(`ticket's delegation chain is deeper than ${MAX_ACT_DEPTH}`);
137
+ if (depth > MAX_ACT_DEPTH) throw new chunkQFUIWC2Q_cjs.SsoError(`ticket's delegation chain is deeper than ${MAX_ACT_DEPTH}`);
138
138
  const link = raw;
139
139
  if (!link || typeof link !== "object" || typeof link.sub !== "string" || link.sub === "") {
140
- throw new chunk2XMKZWC6_cjs.SsoError(`ticket's act (link ${depth}) has no string sub`);
140
+ throw new chunkQFUIWC2Q_cjs.SsoError(`ticket's act (link ${depth}) has no string sub`);
141
141
  }
142
142
  return link.act === void 0 ? { sub: link.sub } : { sub: link.sub, act: readActor(link.act, depth + 1) };
143
143
  }
144
144
 
145
145
  Object.defineProperty(exports, "AVATAR_TYPES", {
146
146
  enumerable: true,
147
- get: function () { return chunk2XMKZWC6_cjs.AVATAR_TYPES; }
147
+ get: function () { return chunkQFUIWC2Q_cjs.AVATAR_TYPES; }
148
148
  });
149
149
  Object.defineProperty(exports, "DEFAULT_ISSUER", {
150
150
  enumerable: true,
151
- get: function () { return chunk2XMKZWC6_cjs.DEFAULT_ISSUER; }
151
+ get: function () { return chunkQFUIWC2Q_cjs.DEFAULT_ISSUER; }
152
152
  });
153
153
  Object.defineProperty(exports, "DEFAULT_SESSION_MAX_AGE", {
154
154
  enumerable: true,
155
- get: function () { return chunk2XMKZWC6_cjs.DEFAULT_SESSION_MAX_AGE; }
155
+ get: function () { return chunkQFUIWC2Q_cjs.DEFAULT_SESSION_MAX_AGE; }
156
156
  });
157
157
  Object.defineProperty(exports, "EMBEDDED_FLOW_MAX_AGE", {
158
158
  enumerable: true,
159
- get: function () { return chunk2XMKZWC6_cjs.EMBEDDED_FLOW_MAX_AGE; }
159
+ get: function () { return chunkQFUIWC2Q_cjs.EMBEDDED_FLOW_MAX_AGE; }
160
160
  });
161
161
  Object.defineProperty(exports, "FLY_CLIENT_ASSERTION_TYPE", {
162
162
  enumerable: true,
163
- get: function () { return chunk2XMKZWC6_cjs.FLY_CLIENT_ASSERTION_TYPE; }
163
+ get: function () { return chunkQFUIWC2Q_cjs.FLY_CLIENT_ASSERTION_TYPE; }
164
164
  });
165
165
  Object.defineProperty(exports, "JwksError", {
166
166
  enumerable: true,
167
- get: function () { return chunk2XMKZWC6_cjs.JwksError; }
167
+ get: function () { return chunkQFUIWC2Q_cjs.JwksError; }
168
168
  });
169
169
  Object.defineProperty(exports, "JwksUnavailableError", {
170
170
  enumerable: true,
171
- get: function () { return chunk2XMKZWC6_cjs.JwksUnavailableError; }
171
+ get: function () { return chunkQFUIWC2Q_cjs.JwksUnavailableError; }
172
172
  });
173
173
  Object.defineProperty(exports, "JwksUnknownKeyError", {
174
174
  enumerable: true,
175
- get: function () { return chunk2XMKZWC6_cjs.JwksUnknownKeyError; }
175
+ get: function () { return chunkQFUIWC2Q_cjs.JwksUnknownKeyError; }
176
176
  });
177
177
  Object.defineProperty(exports, "MAX_AVATAR_BYTES", {
178
178
  enumerable: true,
179
- get: function () { return chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES; }
179
+ get: function () { return chunkQFUIWC2Q_cjs.MAX_AVATAR_BYTES; }
180
180
  });
181
181
  Object.defineProperty(exports, "MAX_INVITATIONS", {
182
182
  enumerable: true,
183
- get: function () { return chunk2XMKZWC6_cjs.MAX_INVITATIONS; }
183
+ get: function () { return chunkQFUIWC2Q_cjs.MAX_INVITATIONS; }
184
184
  });
185
185
  Object.defineProperty(exports, "NoWorkloadIdentityError", {
186
186
  enumerable: true,
187
- get: function () { return chunk2XMKZWC6_cjs.NoWorkloadIdentityError; }
187
+ get: function () { return chunkQFUIWC2Q_cjs.NoWorkloadIdentityError; }
188
188
  });
189
189
  Object.defineProperty(exports, "SsoAppApiError", {
190
190
  enumerable: true,
191
- get: function () { return chunk2XMKZWC6_cjs.SsoAppApiError; }
191
+ get: function () { return chunkQFUIWC2Q_cjs.SsoAppApiError; }
192
192
  });
193
193
  Object.defineProperty(exports, "SsoAvatarRejectedError", {
194
194
  enumerable: true,
195
- get: function () { return chunk2XMKZWC6_cjs.SsoAvatarRejectedError; }
195
+ get: function () { return chunkQFUIWC2Q_cjs.SsoAvatarRejectedError; }
196
196
  });
197
197
  Object.defineProperty(exports, "SsoConfigError", {
198
198
  enumerable: true,
199
- get: function () { return chunk2XMKZWC6_cjs.SsoConfigError; }
199
+ get: function () { return chunkQFUIWC2Q_cjs.SsoConfigError; }
200
200
  });
201
201
  Object.defineProperty(exports, "SsoError", {
202
202
  enumerable: true,
203
- get: function () { return chunk2XMKZWC6_cjs.SsoError; }
203
+ get: function () { return chunkQFUIWC2Q_cjs.SsoError; }
204
204
  });
205
205
  Object.defineProperty(exports, "SsoInsufficientScopeError", {
206
206
  enumerable: true,
207
- get: function () { return chunk2XMKZWC6_cjs.SsoInsufficientScopeError; }
207
+ get: function () { return chunkQFUIWC2Q_cjs.SsoInsufficientScopeError; }
208
208
  });
209
209
  Object.defineProperty(exports, "SsoIntrospectionUnavailableError", {
210
210
  enumerable: true,
211
- get: function () { return chunk2XMKZWC6_cjs.SsoIntrospectionUnavailableError; }
211
+ get: function () { return chunkQFUIWC2Q_cjs.SsoIntrospectionUnavailableError; }
212
212
  });
213
213
  Object.defineProperty(exports, "SsoReauthError", {
214
214
  enumerable: true,
215
- get: function () { return chunk2XMKZWC6_cjs.SsoReauthError; }
215
+ get: function () { return chunkQFUIWC2Q_cjs.SsoReauthError; }
216
216
  });
217
217
  Object.defineProperty(exports, "SsoTokenInactiveError", {
218
218
  enumerable: true,
219
- get: function () { return chunk2XMKZWC6_cjs.SsoTokenInactiveError; }
219
+ get: function () { return chunkQFUIWC2Q_cjs.SsoTokenInactiveError; }
220
220
  });
221
221
  Object.defineProperty(exports, "TicketExchangeError", {
222
222
  enumerable: true,
223
- get: function () { return chunk2XMKZWC6_cjs.TicketExchangeError; }
223
+ get: function () { return chunkQFUIWC2Q_cjs.TicketExchangeError; }
224
224
  });
225
225
  Object.defineProperty(exports, "TicketUnavailableError", {
226
226
  enumerable: true,
227
- get: function () { return chunk2XMKZWC6_cjs.TicketUnavailableError; }
227
+ get: function () { return chunkQFUIWC2Q_cjs.TicketUnavailableError; }
228
228
  });
229
229
  Object.defineProperty(exports, "accessTokenHash", {
230
230
  enumerable: true,
231
- get: function () { return chunk2XMKZWC6_cjs.accessTokenHash; }
231
+ get: function () { return chunkQFUIWC2Q_cjs.accessTokenHash; }
232
232
  });
233
233
  Object.defineProperty(exports, "cookieHeader", {
234
234
  enumerable: true,
235
- get: function () { return chunk2XMKZWC6_cjs.cookieHeader; }
235
+ get: function () { return chunkQFUIWC2Q_cjs.cookieHeader; }
236
236
  });
237
237
  Object.defineProperty(exports, "createDpopKey", {
238
238
  enumerable: true,
239
- get: function () { return chunk2XMKZWC6_cjs.createDpopKey; }
239
+ get: function () { return chunkQFUIWC2Q_cjs.createDpopKey; }
240
240
  });
241
241
  Object.defineProperty(exports, "createDpopProof", {
242
242
  enumerable: true,
243
- get: function () { return chunk2XMKZWC6_cjs.createDpopProof; }
243
+ get: function () { return chunkQFUIWC2Q_cjs.createDpopProof; }
244
244
  });
245
245
  Object.defineProperty(exports, "createJwksCache", {
246
246
  enumerable: true,
247
- get: function () { return chunk2XMKZWC6_cjs.createJwksCache; }
247
+ get: function () { return chunkQFUIWC2Q_cjs.createJwksCache; }
248
248
  });
249
249
  Object.defineProperty(exports, "createMemoryReplayStore", {
250
250
  enumerable: true,
251
- get: function () { return chunk2XMKZWC6_cjs.createMemoryReplayStore; }
251
+ get: function () { return chunkQFUIWC2Q_cjs.createMemoryReplayStore; }
252
252
  });
253
253
  Object.defineProperty(exports, "createSsoClient", {
254
254
  enumerable: true,
255
- get: function () { return chunk2XMKZWC6_cjs.createSsoClient; }
255
+ get: function () { return chunkQFUIWC2Q_cjs.createSsoClient; }
256
256
  });
257
257
  Object.defineProperty(exports, "createTicketClient", {
258
258
  enumerable: true,
259
- get: function () { return chunk2XMKZWC6_cjs.createTicketClient; }
259
+ get: function () { return chunkQFUIWC2Q_cjs.createTicketClient; }
260
260
  });
261
261
  Object.defineProperty(exports, "exchangeUserToken", {
262
262
  enumerable: true,
263
- get: function () { return chunk2XMKZWC6_cjs.exchangeUserToken; }
263
+ get: function () { return chunkQFUIWC2Q_cjs.exchangeUserToken; }
264
264
  });
265
265
  Object.defineProperty(exports, "fetchTicket", {
266
266
  enumerable: true,
267
- get: function () { return chunk2XMKZWC6_cjs.fetchTicket; }
267
+ get: function () { return chunkQFUIWC2Q_cjs.fetchTicket; }
268
268
  });
269
269
  Object.defineProperty(exports, "loadSsoConfig", {
270
270
  enumerable: true,
271
- get: function () { return chunk2XMKZWC6_cjs.loadSsoConfig; }
271
+ get: function () { return chunkQFUIWC2Q_cjs.loadSsoConfig; }
272
272
  });
273
273
  Object.defineProperty(exports, "memoryTokenStore", {
274
274
  enumerable: true,
275
- get: function () { return chunk2XMKZWC6_cjs.memoryTokenStore; }
275
+ get: function () { return chunkQFUIWC2Q_cjs.memoryTokenStore; }
276
276
  });
277
277
  Object.defineProperty(exports, "normalizeHtu", {
278
278
  enumerable: true,
279
- get: function () { return chunk2XMKZWC6_cjs.normalizeHtu; }
279
+ get: function () { return chunkQFUIWC2Q_cjs.normalizeHtu; }
280
280
  });
281
281
  Object.defineProperty(exports, "openEmbeddedFlow", {
282
282
  enumerable: true,
283
- get: function () { return chunk2XMKZWC6_cjs.openEmbeddedFlow; }
283
+ get: function () { return chunkQFUIWC2Q_cjs.openEmbeddedFlow; }
284
284
  });
285
285
  Object.defineProperty(exports, "readCookie", {
286
286
  enumerable: true,
287
- get: function () { return chunk2XMKZWC6_cjs.readCookie; }
287
+ get: function () { return chunkQFUIWC2Q_cjs.readCookie; }
288
288
  });
289
289
  Object.defineProperty(exports, "sealEmbeddedFlow", {
290
290
  enumerable: true,
291
- get: function () { return chunk2XMKZWC6_cjs.sealEmbeddedFlow; }
291
+ get: function () { return chunkQFUIWC2Q_cjs.sealEmbeddedFlow; }
292
292
  });
293
293
  Object.defineProperty(exports, "signSession", {
294
294
  enumerable: true,
295
- get: function () { return chunk2XMKZWC6_cjs.signSession; }
295
+ get: function () { return chunkQFUIWC2Q_cjs.signSession; }
296
296
  });
297
297
  Object.defineProperty(exports, "signValue", {
298
298
  enumerable: true,
299
- get: function () { return chunk2XMKZWC6_cjs.signValue; }
299
+ get: function () { return chunkQFUIWC2Q_cjs.signValue; }
300
300
  });
301
301
  Object.defineProperty(exports, "verifyDpopProof", {
302
302
  enumerable: true,
303
- get: function () { return chunk2XMKZWC6_cjs.verifyDpopProof; }
303
+ get: function () { return chunkQFUIWC2Q_cjs.verifyDpopProof; }
304
304
  });
305
305
  Object.defineProperty(exports, "verifySession", {
306
306
  enumerable: true,
307
- get: function () { return chunk2XMKZWC6_cjs.verifySession; }
307
+ get: function () { return chunkQFUIWC2Q_cjs.verifySession; }
308
308
  });
309
309
  Object.defineProperty(exports, "verifyValue", {
310
310
  enumerable: true,
311
- get: function () { return chunk2XMKZWC6_cjs.verifyValue; }
311
+ get: function () { return chunkQFUIWC2Q_cjs.verifyValue; }
312
312
  });
313
313
  exports.MAX_ACT_DEPTH = MAX_ACT_DEPTH;
314
314
  exports.TICKET_FORMAT_VERSION = TICKET_FORMAT_VERSION;
package/dist/index.d.cts CHANGED
@@ -134,7 +134,7 @@ interface ExchangeUserTokenOptions {
134
134
  issuer?: string;
135
135
  /** The app that holds the user's token — it must be the token's own client (BID refuses otherwise). */
136
136
  clientId: string;
137
- /** A confidential app proves itself with its secret (Basic). A public app (an extension) omits it. */
137
+ /** A confidential app proves itself with its secret (in the form body, client_secret_post). A public app (an extension) omits it. */
138
138
  clientSecret?: string;
139
139
  /** The user's BID access token. Never logged, never in an error. */
140
140
  subjectToken: string;
package/dist/index.d.ts CHANGED
@@ -134,7 +134,7 @@ interface ExchangeUserTokenOptions {
134
134
  issuer?: string;
135
135
  /** The app that holds the user's token — it must be the token's own client (BID refuses otherwise). */
136
136
  clientId: string;
137
- /** A confidential app proves itself with its secret (Basic). A public app (an extension) omits it. */
137
+ /** A confidential app proves itself with its secret (in the form body, client_secret_post). A public app (an extension) omits it. */
138
138
  clientSecret?: string;
139
139
  /** The user's BID access token. Never logged, never in an error. */
140
140
  subjectToken: string;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { createMemoryReplayStore, SsoError, ALLOWED_ALGS, JwksUnavailableError, verifyDpopProof, createJwksCache } from './chunk-UDUPP35Z.js';
2
- export { AVATAR_TYPES, DEFAULT_ISSUER, DEFAULT_SESSION_MAX_AGE, EMBEDDED_FLOW_MAX_AGE, FLY_CLIENT_ASSERTION_TYPE, JwksError, JwksUnavailableError, JwksUnknownKeyError, MAX_AVATAR_BYTES, MAX_INVITATIONS, NoWorkloadIdentityError, SsoAppApiError, SsoAvatarRejectedError, SsoConfigError, SsoError, SsoInsufficientScopeError, SsoIntrospectionUnavailableError, SsoReauthError, SsoTokenInactiveError, TicketExchangeError, TicketUnavailableError, accessTokenHash, cookieHeader, createDpopKey, createDpopProof, createJwksCache, createMemoryReplayStore, createSsoClient, createTicketClient, exchangeUserToken, fetchTicket, loadSsoConfig, memoryTokenStore, normalizeHtu, openEmbeddedFlow, readCookie, sealEmbeddedFlow, signSession, signValue, verifyDpopProof, verifySession, verifyValue } from './chunk-UDUPP35Z.js';
1
+ import { createMemoryReplayStore, SsoError, ALLOWED_ALGS, JwksUnavailableError, verifyDpopProof, createJwksCache } from './chunk-NIYOPNRE.js';
2
+ export { AVATAR_TYPES, DEFAULT_ISSUER, DEFAULT_SESSION_MAX_AGE, EMBEDDED_FLOW_MAX_AGE, FLY_CLIENT_ASSERTION_TYPE, JwksError, JwksUnavailableError, JwksUnknownKeyError, MAX_AVATAR_BYTES, MAX_INVITATIONS, NoWorkloadIdentityError, SsoAppApiError, SsoAvatarRejectedError, SsoConfigError, SsoError, SsoInsufficientScopeError, SsoIntrospectionUnavailableError, SsoReauthError, SsoTokenInactiveError, TicketExchangeError, TicketUnavailableError, accessTokenHash, cookieHeader, createDpopKey, createDpopProof, createJwksCache, createMemoryReplayStore, createSsoClient, createTicketClient, exchangeUserToken, fetchTicket, loadSsoConfig, memoryTokenStore, normalizeHtu, openEmbeddedFlow, readCookie, sealEmbeddedFlow, signSession, signValue, verifyDpopProof, verifySession, verifyValue } from './chunk-NIYOPNRE.js';
3
3
  import { decodeProtectedHeader, jwtVerify } from 'jose';
4
4
 
5
5
  var PRINCIPAL_TYPES = ["human", "service", "agent", "user"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@broberg/sso",
3
- "version": "0.21.0",
3
+ "version": "0.21.2",
4
4
  "description": "The thin client for BrobergID — send a user to central login, verify the ID token against JWKS, keep a local session. Public client + PKCE only: no passwords, no passkeys, no client secret can live in an app.",
5
5
  "type": "module",
6
6
  "license": "MIT",