@broberg/sso 0.19.1 → 0.21.0
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/README.md +54 -0
- package/dist/{chunk-2F3RPYJV.cjs → chunk-2XMKZWC6.cjs} +314 -7
- package/dist/chunk-2XMKZWC6.cjs.map +1 -0
- package/dist/{chunk-CCDRB6NJ.js → chunk-UDUPP35Z.js} +302 -9
- package/dist/chunk-UDUPP35Z.js.map +1 -0
- package/dist/hono.cjs +38 -37
- package/dist/hono.cjs.map +1 -1
- package/dist/hono.d.cts +7 -1
- package/dist/hono.d.ts +7 -1
- package/dist/hono.js +3 -2
- package/dist/hono.js.map +1 -1
- package/dist/index.cjs +112 -291
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -60
- package/dist/index.d.ts +95 -60
- package/dist/index.js +4 -227
- package/dist/index.js.map +1 -1
- package/dist/{session-qvhMg3ID.d.cts → session-DnotfVNd.d.cts} +26 -1
- package/dist/{session-qvhMg3ID.d.ts → session-DnotfVNd.d.ts} +26 -1
- package/package.json +1 -1
- package/dist/chunk-2F3RPYJV.cjs.map +0 -1
- package/dist/chunk-CCDRB6NJ.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,231 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var fs = require('fs');
|
|
5
|
-
var http = require('http');
|
|
3
|
+
var chunk2XMKZWC6_cjs = require('./chunk-2XMKZWC6.cjs');
|
|
6
4
|
var jose = require('jose');
|
|
7
5
|
|
|
8
|
-
async function createDpopKey() {
|
|
9
|
-
const { privateKey, publicKey } = await jose.generateKeyPair("ES256", { extractable: false });
|
|
10
|
-
const jwk = await jose.exportJWK(publicKey);
|
|
11
|
-
const publicJwk = { kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y };
|
|
12
|
-
return { privateKey, publicJwk, jkt: await jose.calculateJwkThumbprint(publicJwk) };
|
|
13
|
-
}
|
|
14
|
-
var enc = new TextEncoder();
|
|
15
|
-
var b64url = (bytes) => btoa(String.fromCharCode(...new Uint8Array(bytes))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
16
|
-
async function accessTokenHash(ticket) {
|
|
17
|
-
return b64url(await crypto.subtle.digest("SHA-256", enc.encode(ticket)));
|
|
18
|
-
}
|
|
19
|
-
function normalizeHtu(url) {
|
|
20
|
-
const u = new URL(url);
|
|
21
|
-
return `${u.protocol}//${u.host}${u.pathname}`;
|
|
22
|
-
}
|
|
23
|
-
async function createDpopProof(key, opts) {
|
|
24
|
-
const payload = {
|
|
25
|
-
jti: crypto.randomUUID(),
|
|
26
|
-
htm: opts.method.toUpperCase(),
|
|
27
|
-
htu: normalizeHtu(opts.url),
|
|
28
|
-
iat: Math.floor((opts.now?.() ?? Date.now()) / 1e3)
|
|
29
|
-
};
|
|
30
|
-
if (opts.ticket !== void 0) payload.ath = await accessTokenHash(opts.ticket);
|
|
31
|
-
return new jose.SignJWT(payload).setProtectedHeader({ typ: "dpop+jwt", alg: "ES256", jwk: key.publicJwk }).sign(key.privateKey);
|
|
32
|
-
}
|
|
33
|
-
function createMemoryReplayStore(now = () => Date.now()) {
|
|
34
|
-
const entries = /* @__PURE__ */ new Map();
|
|
35
|
-
return {
|
|
36
|
-
async seen(key, ttlMs) {
|
|
37
|
-
const t = now();
|
|
38
|
-
for (const [k, until] of entries) if (until <= t) entries.delete(k);
|
|
39
|
-
if (entries.has(key)) return true;
|
|
40
|
-
entries.set(key, t + ttlMs);
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
var ASYMMETRIC = /* @__PURE__ */ new Set(["ES256", "ES384", "ES512", "EdDSA", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"]);
|
|
46
|
-
async function verifyDpopProof(proof, o) {
|
|
47
|
-
let header;
|
|
48
|
-
try {
|
|
49
|
-
header = jose.decodeProtectedHeader(proof);
|
|
50
|
-
} catch {
|
|
51
|
-
throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof is not a JWS");
|
|
52
|
-
}
|
|
53
|
-
if (header.typ !== "dpop+jwt") throw new chunk2F3RPYJV_cjs.SsoError(`DPoP proof has typ ${JSON.stringify(header.typ)}, not "dpop+jwt"`);
|
|
54
|
-
if (!header.alg || !ASYMMETRIC.has(header.alg)) throw new chunk2F3RPYJV_cjs.SsoError(`DPoP proof alg ${JSON.stringify(header.alg)} is not an accepted asymmetric algorithm`);
|
|
55
|
-
const jwk = header.jwk;
|
|
56
|
-
if (!jwk || typeof jwk !== "object") throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof carries no jwk");
|
|
57
|
-
if ("d" in jwk) throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof jwk contains a private key");
|
|
58
|
-
let payload;
|
|
59
|
-
try {
|
|
60
|
-
const key = await jose.importJWK(jwk, header.alg);
|
|
61
|
-
({ payload } = await jose.jwtVerify(proof, key, { typ: "dpop+jwt", algorithms: [header.alg] }));
|
|
62
|
-
} catch (e) {
|
|
63
|
-
throw new chunk2F3RPYJV_cjs.SsoError(`DPoP proof signature rejected: ${e instanceof Error ? e.message : String(e)}`);
|
|
64
|
-
}
|
|
65
|
-
if (await jose.calculateJwkThumbprint(jwk) !== o.jkt) throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof key does not match the ticket's cnf.jkt");
|
|
66
|
-
if (payload.htm !== o.method.toUpperCase()) throw new chunk2F3RPYJV_cjs.SsoError(`DPoP proof is for ${JSON.stringify(payload.htm)}, the request is ${o.method.toUpperCase()}`);
|
|
67
|
-
let htu;
|
|
68
|
-
try {
|
|
69
|
-
htu = normalizeHtu(String(payload.htu));
|
|
70
|
-
} catch {
|
|
71
|
-
throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof htu is not a URL");
|
|
72
|
-
}
|
|
73
|
-
if (htu !== normalizeHtu(o.url)) throw new chunk2F3RPYJV_cjs.SsoError(`DPoP proof is for ${htu}, the request is ${normalizeHtu(o.url)}`);
|
|
74
|
-
const nowSec = Math.floor(o.now() / 1e3);
|
|
75
|
-
if (typeof payload.iat !== "number" || Math.abs(nowSec - payload.iat) > o.iatWindowSec) {
|
|
76
|
-
throw new chunk2F3RPYJV_cjs.SsoError(`DPoP proof iat is outside \xB1${o.iatWindowSec}s`);
|
|
77
|
-
}
|
|
78
|
-
if (payload.ath !== await accessTokenHash(o.ticket)) throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof ath does not match this ticket");
|
|
79
|
-
if (typeof payload.jti !== "string" || payload.jti === "") throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof has no jti");
|
|
80
|
-
if (await o.replay.seen(`${o.jkt}:${payload.jti}`, o.iatWindowSec * 2 * 1e3)) {
|
|
81
|
-
throw new chunk2F3RPYJV_cjs.SsoError("DPoP proof was already used (jti replay)");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// src/fetch-ticket.ts
|
|
86
|
-
var DEFAULT_ISSUER = "https://id.broberg.ai";
|
|
87
|
-
var FLY_SOCKET = "/.fly/api";
|
|
88
|
-
var NoWorkloadIdentityError = class extends Error {
|
|
89
|
-
constructor(message) {
|
|
90
|
-
super(message);
|
|
91
|
-
this.name = "NoWorkloadIdentityError";
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
var TicketExchangeError = class extends Error {
|
|
95
|
-
constructor(message, code, status) {
|
|
96
|
-
super(message);
|
|
97
|
-
this.code = code;
|
|
98
|
-
this.status = status;
|
|
99
|
-
this.name = "TicketExchangeError";
|
|
100
|
-
}
|
|
101
|
-
code;
|
|
102
|
-
status;
|
|
103
|
-
};
|
|
104
|
-
var TicketUnavailableError = class extends Error {
|
|
105
|
-
constructor(message) {
|
|
106
|
-
super(message);
|
|
107
|
-
this.name = "TicketUnavailableError";
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
function flyOidcOverSocket(aud) {
|
|
111
|
-
return new Promise((resolve, reject) => {
|
|
112
|
-
const body = JSON.stringify({ aud });
|
|
113
|
-
const req = http.request(
|
|
114
|
-
{ socketPath: FLY_SOCKET, path: "/v1/tokens/oidc", method: "POST", headers: { "content-type": "application/json", "content-length": Buffer.byteLength(body) } },
|
|
115
|
-
(res) => {
|
|
116
|
-
let data = "";
|
|
117
|
-
res.setEncoding("utf8");
|
|
118
|
-
res.on("data", (c) => data += c);
|
|
119
|
-
res.on("end", () => {
|
|
120
|
-
if ((res.statusCode ?? 0) >= 200 && (res.statusCode ?? 0) < 300) resolve(data.trim());
|
|
121
|
-
else reject(new TicketUnavailableError(`Fly OIDC answered ${res.statusCode}`));
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
);
|
|
125
|
-
req.on("error", (e) => reject(new TicketUnavailableError(`Fly OIDC socket: ${e.message}`)));
|
|
126
|
-
req.end(body);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
function jwtExp(token) {
|
|
130
|
-
try {
|
|
131
|
-
const payload = JSON.parse(Buffer.from(token.split(".")[1] ?? "", "base64url").toString("utf8"));
|
|
132
|
-
return typeof payload.exp === "number" ? payload.exp : null;
|
|
133
|
-
} catch {
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
function createTicketClient(options = {}) {
|
|
138
|
-
const issuer = (options.issuer ?? DEFAULT_ISSUER).replace(/\/+$/, "");
|
|
139
|
-
const renewBeforeSec = options.renewBeforeSec ?? 30;
|
|
140
|
-
const env = options.env ?? process.env;
|
|
141
|
-
const fetchImpl = options.fetchImpl ?? fetch;
|
|
142
|
-
const now = options.now ?? (() => Date.now());
|
|
143
|
-
const flyOidc = options.flyOidc ?? flyOidcOverSocket;
|
|
144
|
-
const onFly = options.onFly ?? (() => !!env.FLY_APP_NAME && fs.existsSync(FLY_SOCKET));
|
|
145
|
-
const cache = /* @__PURE__ */ new Map();
|
|
146
|
-
const inFlight = /* @__PURE__ */ new Map();
|
|
147
|
-
let dpopKey = null;
|
|
148
|
-
const ownKey = () => dpopKey ??= createDpopKey();
|
|
149
|
-
async function platformToken() {
|
|
150
|
-
if (onFly()) return flyOidc(issuer);
|
|
151
|
-
const url = env.ACTIONS_ID_TOKEN_REQUEST_URL;
|
|
152
|
-
const bearer = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
|
|
153
|
-
if (url && bearer) {
|
|
154
|
-
let res;
|
|
155
|
-
try {
|
|
156
|
-
res = await fetchImpl(`${url}&audience=${encodeURIComponent(issuer)}`, { headers: { authorization: `Bearer ${bearer}` } });
|
|
157
|
-
} catch (e) {
|
|
158
|
-
throw new TicketUnavailableError(`GitHub OIDC endpoint unreachable: ${e instanceof Error ? e.message : String(e)}`);
|
|
159
|
-
}
|
|
160
|
-
if (!res.ok) throw new TicketUnavailableError(`GitHub OIDC endpoint answered ${res.status}`);
|
|
161
|
-
const { value } = await res.json();
|
|
162
|
-
if (!value) throw new TicketUnavailableError("GitHub OIDC endpoint returned no token");
|
|
163
|
-
return value;
|
|
164
|
-
}
|
|
165
|
-
throw new NoWorkloadIdentityError(
|
|
166
|
-
"No workload identity to exchange for a ticket: not on a Fly machine (FLY_APP_NAME + /.fly/api) and not in a GitHub Actions job (ACTIONS_ID_TOKEN_REQUEST_URL/_TOKEN \u2014 add `permissions: id-token: write`). A Mac session keeps using its session key."
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
async function exchange(audience, scope) {
|
|
170
|
-
const subject = await platformToken();
|
|
171
|
-
const form = new URLSearchParams({
|
|
172
|
-
grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
173
|
-
subject_token: subject,
|
|
174
|
-
subject_token_type: "urn:ietf:params:oauth:token-type:jwt",
|
|
175
|
-
audience
|
|
176
|
-
});
|
|
177
|
-
if (scope) form.set("scope", scope);
|
|
178
|
-
let res;
|
|
179
|
-
try {
|
|
180
|
-
const tokenUrl = `${issuer}/oauth2/token`;
|
|
181
|
-
const headers = { "content-type": "application/x-www-form-urlencoded" };
|
|
182
|
-
if (options.dpop) headers.dpop = await createDpopProof(await ownKey(), { method: "POST", url: tokenUrl, now });
|
|
183
|
-
res = await fetchImpl(tokenUrl, { method: "POST", headers, body: form });
|
|
184
|
-
} catch (e) {
|
|
185
|
-
throw new TicketUnavailableError(`${issuer} unreachable: ${e instanceof Error ? e.message : String(e)}`);
|
|
186
|
-
}
|
|
187
|
-
let body = {};
|
|
188
|
-
try {
|
|
189
|
-
body = await res.json();
|
|
190
|
-
} catch {
|
|
191
|
-
}
|
|
192
|
-
if (res.status >= 500) throw new TicketUnavailableError(`${issuer} answered ${res.status}`);
|
|
193
|
-
if (!res.ok || !body.access_token) {
|
|
194
|
-
const desc = body.error_description ?? "";
|
|
195
|
-
const code = desc.includes(":") ? desc.slice(0, desc.indexOf(":")).trim() : body.error ?? "exchange_refused";
|
|
196
|
-
throw new TicketExchangeError(`BID refused the ticket for ${audience}: ${desc || body.error || res.status}`, code, res.status);
|
|
197
|
-
}
|
|
198
|
-
const nowSec = Math.floor(now() / 1e3);
|
|
199
|
-
const exp = jwtExp(body.access_token) ?? nowSec + (body.expires_in ?? 300);
|
|
200
|
-
return { token: body.access_token, exp };
|
|
201
|
-
}
|
|
202
|
-
const client = {
|
|
203
|
-
async authHeaders({ audience, scope, method, url }) {
|
|
204
|
-
const ticket = await client.get({ audience, scope });
|
|
205
|
-
if (!options.dpop) return { authorization: `Bearer ${ticket}` };
|
|
206
|
-
return { authorization: `DPoP ${ticket}`, dpop: await createDpopProof(await ownKey(), { method, url, ticket, now }) };
|
|
207
|
-
},
|
|
208
|
-
async get({ audience, scope }) {
|
|
209
|
-
const key = `${audience} ${scope ?? ""}`;
|
|
210
|
-
const hit = cache.get(key);
|
|
211
|
-
if (hit && hit.exp - renewBeforeSec > now() / 1e3) return hit.token;
|
|
212
|
-
const pending = inFlight.get(key);
|
|
213
|
-
if (pending) return pending;
|
|
214
|
-
const p = exchange(audience, scope).then((t) => {
|
|
215
|
-
cache.set(key, t);
|
|
216
|
-
return t.token;
|
|
217
|
-
}).finally(() => inFlight.delete(key));
|
|
218
|
-
inFlight.set(key, p);
|
|
219
|
-
return p;
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
return client;
|
|
223
|
-
}
|
|
224
|
-
var shared = null;
|
|
225
|
-
function fetchTicket(opts) {
|
|
226
|
-
shared ??= createTicketClient();
|
|
227
|
-
return shared.get(opts);
|
|
228
|
-
}
|
|
229
6
|
var PRINCIPAL_TYPES = ["human", "service", "agent", "user"];
|
|
230
7
|
var TICKET_FORMAT_VERSION = 1;
|
|
231
8
|
var MAX_ACT_DEPTH = 5;
|
|
@@ -240,11 +17,11 @@ function createTicketVerifier(options) {
|
|
|
240
17
|
dpopIatWindowSec = 60,
|
|
241
18
|
now = () => Date.now()
|
|
242
19
|
} = options;
|
|
243
|
-
const replayStore = options.replayStore ?? createMemoryReplayStore(now);
|
|
244
|
-
if (!issuer) throw new
|
|
245
|
-
if (!audience) throw new
|
|
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");
|
|
246
23
|
let cachePromise = null;
|
|
247
|
-
const cacheFor = (jwksUri) =>
|
|
24
|
+
const cacheFor = (jwksUri) => chunk2XMKZWC6_cjs.createJwksCache({
|
|
248
25
|
jwksUri,
|
|
249
26
|
fetchImpl,
|
|
250
27
|
...options.warmUp ? { warmUp: true } : {},
|
|
@@ -260,12 +37,12 @@ function createTicketVerifier(options) {
|
|
|
260
37
|
if (!res.ok) throw new Error(`answered ${res.status}`);
|
|
261
38
|
doc = await res.json();
|
|
262
39
|
} catch (cause) {
|
|
263
|
-
throw new
|
|
40
|
+
throw new chunk2XMKZWC6_cjs.JwksUnavailableError(`${url}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
264
41
|
}
|
|
265
42
|
if (doc.issuer !== issuer) {
|
|
266
|
-
throw new
|
|
43
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`issuer is ${issuer} but ${url} says ${doc.issuer} \u2014 they must match exactly`);
|
|
267
44
|
}
|
|
268
|
-
if (!doc.jwks_uri) throw new
|
|
45
|
+
if (!doc.jwks_uri) throw new chunk2XMKZWC6_cjs.SsoError(`${url} names no jwks_uri`);
|
|
269
46
|
return cacheFor(doc.jwks_uri);
|
|
270
47
|
})().catch((err) => {
|
|
271
48
|
cachePromise = null;
|
|
@@ -281,52 +58,52 @@ function createTicketVerifier(options) {
|
|
|
281
58
|
try {
|
|
282
59
|
header = jose.decodeProtectedHeader(token);
|
|
283
60
|
} catch {
|
|
284
|
-
throw new
|
|
61
|
+
throw new chunk2XMKZWC6_cjs.SsoError("ticket is not a JWS");
|
|
285
62
|
}
|
|
286
|
-
if (!header.kid) throw new
|
|
287
|
-
if (header.typ === "logout+jwt") throw new
|
|
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");
|
|
288
65
|
const cache = await keys();
|
|
289
66
|
let payload;
|
|
290
67
|
try {
|
|
291
68
|
({ payload } = await jose.jwtVerify(token, async () => cache.getKey(header.kid, header.alg ?? "EdDSA"), {
|
|
292
69
|
issuer,
|
|
293
70
|
audience,
|
|
294
|
-
algorithms:
|
|
71
|
+
algorithms: chunk2XMKZWC6_cjs.ALLOWED_ALGS,
|
|
295
72
|
clockTolerance: clockToleranceSec,
|
|
296
73
|
requiredClaims: ["exp", "iat", "jti", "sub"]
|
|
297
74
|
}));
|
|
298
75
|
} catch (e) {
|
|
299
|
-
if (e instanceof
|
|
300
|
-
throw new
|
|
76
|
+
if (e instanceof chunk2XMKZWC6_cjs.JwksUnavailableError) throw e;
|
|
77
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`ticket rejected: ${e instanceof Error ? e.message : String(e)}`);
|
|
301
78
|
}
|
|
302
|
-
if ("events" in payload) throw new
|
|
303
|
-
if ("nonce" in payload) throw new
|
|
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");
|
|
304
81
|
const type = payload.principal_type;
|
|
305
82
|
if (typeof type !== "string" || !PRINCIPAL_TYPES.includes(type)) {
|
|
306
|
-
throw new
|
|
83
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`ticket has no valid principal_type (got ${JSON.stringify(type)})`);
|
|
307
84
|
}
|
|
308
85
|
const lifetime = payload.exp - payload.iat;
|
|
309
86
|
if (lifetime > maxLifetimeSec) {
|
|
310
|
-
throw new
|
|
87
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`ticket claims a ${lifetime}s lifetime; at most ${maxLifetimeSec}s is accepted`);
|
|
311
88
|
}
|
|
312
|
-
if (typeof payload.sub !== "string" || payload.sub === "") throw new
|
|
89
|
+
if (typeof payload.sub !== "string" || payload.sub === "") throw new chunk2XMKZWC6_cjs.SsoError("ticket has no sub");
|
|
313
90
|
const scopes = typeof payload.scope === "string" ? payload.scope.split(" ").filter(Boolean) : [];
|
|
314
91
|
const required = opts.scope === void 0 ? [] : Array.isArray(opts.scope) ? opts.scope : [opts.scope];
|
|
315
92
|
const missing = required.filter((s) => !scopes.includes(s));
|
|
316
|
-
if (missing.length) throw new
|
|
93
|
+
if (missing.length) throw new chunk2XMKZWC6_cjs.SsoError(`ticket lacks scope ${missing.join(", ")}`);
|
|
317
94
|
const ver = payload.ver === void 0 ? 0 : payload.ver;
|
|
318
95
|
if (typeof ver !== "number" || !Number.isInteger(ver) || ver < 0) {
|
|
319
|
-
throw new
|
|
96
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`ticket has an invalid ver (got ${JSON.stringify(payload.ver)})`);
|
|
320
97
|
}
|
|
321
98
|
if (ver > TICKET_FORMAT_VERSION) {
|
|
322
|
-
throw new
|
|
99
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`ticket format version ${ver} is newer than this @broberg/sso understands (${TICKET_FORMAT_VERSION}) \u2014 upgrade @broberg/sso`);
|
|
323
100
|
}
|
|
324
101
|
const act = payload.act === void 0 ? null : readActor(payload.act, 1);
|
|
325
102
|
const cnfRaw = payload.cnf;
|
|
326
103
|
const cnf = cnfRaw && typeof cnfRaw.jkt === "string" && cnfRaw.jkt ? { jkt: cnfRaw.jkt } : null;
|
|
327
104
|
if (cnf) {
|
|
328
|
-
if (!opts.dpop?.proof) throw new
|
|
329
|
-
await verifyDpopProof(opts.dpop.proof, {
|
|
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, {
|
|
330
107
|
method: opts.dpop.method,
|
|
331
108
|
url: opts.dpop.url,
|
|
332
109
|
ticket: token,
|
|
@@ -336,11 +113,11 @@ function createTicketVerifier(options) {
|
|
|
336
113
|
now
|
|
337
114
|
});
|
|
338
115
|
} else if (requireDpop) {
|
|
339
|
-
throw new
|
|
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)");
|
|
340
117
|
}
|
|
341
118
|
const named = (v) => typeof v === "string" && v ? v : null;
|
|
342
119
|
const clientId = type === "user" ? named(payload.client_id) ?? named(payload.azp) : named(payload.client_id) ?? payload.sub;
|
|
343
|
-
if (clientId === null) throw new
|
|
120
|
+
if (clientId === null) throw new chunk2XMKZWC6_cjs.SsoError("a user ticket names no app (no client_id or azp)");
|
|
344
121
|
return {
|
|
345
122
|
principal: payload.sub,
|
|
346
123
|
type,
|
|
@@ -357,140 +134,184 @@ function createTicketVerifier(options) {
|
|
|
357
134
|
};
|
|
358
135
|
}
|
|
359
136
|
function readActor(raw, depth) {
|
|
360
|
-
if (depth > MAX_ACT_DEPTH) throw new
|
|
137
|
+
if (depth > MAX_ACT_DEPTH) throw new chunk2XMKZWC6_cjs.SsoError(`ticket's delegation chain is deeper than ${MAX_ACT_DEPTH}`);
|
|
361
138
|
const link = raw;
|
|
362
139
|
if (!link || typeof link !== "object" || typeof link.sub !== "string" || link.sub === "") {
|
|
363
|
-
throw new
|
|
140
|
+
throw new chunk2XMKZWC6_cjs.SsoError(`ticket's act (link ${depth}) has no string sub`);
|
|
364
141
|
}
|
|
365
142
|
return link.act === void 0 ? { sub: link.sub } : { sub: link.sub, act: readActor(link.act, depth + 1) };
|
|
366
143
|
}
|
|
367
144
|
|
|
368
145
|
Object.defineProperty(exports, "AVATAR_TYPES", {
|
|
369
146
|
enumerable: true,
|
|
370
|
-
get: function () { return
|
|
147
|
+
get: function () { return chunk2XMKZWC6_cjs.AVATAR_TYPES; }
|
|
148
|
+
});
|
|
149
|
+
Object.defineProperty(exports, "DEFAULT_ISSUER", {
|
|
150
|
+
enumerable: true,
|
|
151
|
+
get: function () { return chunk2XMKZWC6_cjs.DEFAULT_ISSUER; }
|
|
371
152
|
});
|
|
372
153
|
Object.defineProperty(exports, "DEFAULT_SESSION_MAX_AGE", {
|
|
373
154
|
enumerable: true,
|
|
374
|
-
get: function () { return
|
|
155
|
+
get: function () { return chunk2XMKZWC6_cjs.DEFAULT_SESSION_MAX_AGE; }
|
|
375
156
|
});
|
|
376
157
|
Object.defineProperty(exports, "EMBEDDED_FLOW_MAX_AGE", {
|
|
377
158
|
enumerable: true,
|
|
378
|
-
get: function () { return
|
|
159
|
+
get: function () { return chunk2XMKZWC6_cjs.EMBEDDED_FLOW_MAX_AGE; }
|
|
160
|
+
});
|
|
161
|
+
Object.defineProperty(exports, "FLY_CLIENT_ASSERTION_TYPE", {
|
|
162
|
+
enumerable: true,
|
|
163
|
+
get: function () { return chunk2XMKZWC6_cjs.FLY_CLIENT_ASSERTION_TYPE; }
|
|
379
164
|
});
|
|
380
165
|
Object.defineProperty(exports, "JwksError", {
|
|
381
166
|
enumerable: true,
|
|
382
|
-
get: function () { return
|
|
167
|
+
get: function () { return chunk2XMKZWC6_cjs.JwksError; }
|
|
383
168
|
});
|
|
384
169
|
Object.defineProperty(exports, "JwksUnavailableError", {
|
|
385
170
|
enumerable: true,
|
|
386
|
-
get: function () { return
|
|
171
|
+
get: function () { return chunk2XMKZWC6_cjs.JwksUnavailableError; }
|
|
387
172
|
});
|
|
388
173
|
Object.defineProperty(exports, "JwksUnknownKeyError", {
|
|
389
174
|
enumerable: true,
|
|
390
|
-
get: function () { return
|
|
175
|
+
get: function () { return chunk2XMKZWC6_cjs.JwksUnknownKeyError; }
|
|
391
176
|
});
|
|
392
177
|
Object.defineProperty(exports, "MAX_AVATAR_BYTES", {
|
|
393
178
|
enumerable: true,
|
|
394
|
-
get: function () { return
|
|
179
|
+
get: function () { return chunk2XMKZWC6_cjs.MAX_AVATAR_BYTES; }
|
|
395
180
|
});
|
|
396
181
|
Object.defineProperty(exports, "MAX_INVITATIONS", {
|
|
397
182
|
enumerable: true,
|
|
398
|
-
get: function () { return
|
|
183
|
+
get: function () { return chunk2XMKZWC6_cjs.MAX_INVITATIONS; }
|
|
184
|
+
});
|
|
185
|
+
Object.defineProperty(exports, "NoWorkloadIdentityError", {
|
|
186
|
+
enumerable: true,
|
|
187
|
+
get: function () { return chunk2XMKZWC6_cjs.NoWorkloadIdentityError; }
|
|
399
188
|
});
|
|
400
189
|
Object.defineProperty(exports, "SsoAppApiError", {
|
|
401
190
|
enumerable: true,
|
|
402
|
-
get: function () { return
|
|
191
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoAppApiError; }
|
|
403
192
|
});
|
|
404
193
|
Object.defineProperty(exports, "SsoAvatarRejectedError", {
|
|
405
194
|
enumerable: true,
|
|
406
|
-
get: function () { return
|
|
195
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoAvatarRejectedError; }
|
|
407
196
|
});
|
|
408
197
|
Object.defineProperty(exports, "SsoConfigError", {
|
|
409
198
|
enumerable: true,
|
|
410
|
-
get: function () { return
|
|
199
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoConfigError; }
|
|
411
200
|
});
|
|
412
201
|
Object.defineProperty(exports, "SsoError", {
|
|
413
202
|
enumerable: true,
|
|
414
|
-
get: function () { return
|
|
203
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoError; }
|
|
415
204
|
});
|
|
416
205
|
Object.defineProperty(exports, "SsoInsufficientScopeError", {
|
|
417
206
|
enumerable: true,
|
|
418
|
-
get: function () { return
|
|
207
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoInsufficientScopeError; }
|
|
419
208
|
});
|
|
420
209
|
Object.defineProperty(exports, "SsoIntrospectionUnavailableError", {
|
|
421
210
|
enumerable: true,
|
|
422
|
-
get: function () { return
|
|
211
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoIntrospectionUnavailableError; }
|
|
423
212
|
});
|
|
424
213
|
Object.defineProperty(exports, "SsoReauthError", {
|
|
425
214
|
enumerable: true,
|
|
426
|
-
get: function () { return
|
|
215
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoReauthError; }
|
|
427
216
|
});
|
|
428
217
|
Object.defineProperty(exports, "SsoTokenInactiveError", {
|
|
429
218
|
enumerable: true,
|
|
430
|
-
get: function () { return
|
|
219
|
+
get: function () { return chunk2XMKZWC6_cjs.SsoTokenInactiveError; }
|
|
220
|
+
});
|
|
221
|
+
Object.defineProperty(exports, "TicketExchangeError", {
|
|
222
|
+
enumerable: true,
|
|
223
|
+
get: function () { return chunk2XMKZWC6_cjs.TicketExchangeError; }
|
|
224
|
+
});
|
|
225
|
+
Object.defineProperty(exports, "TicketUnavailableError", {
|
|
226
|
+
enumerable: true,
|
|
227
|
+
get: function () { return chunk2XMKZWC6_cjs.TicketUnavailableError; }
|
|
228
|
+
});
|
|
229
|
+
Object.defineProperty(exports, "accessTokenHash", {
|
|
230
|
+
enumerable: true,
|
|
231
|
+
get: function () { return chunk2XMKZWC6_cjs.accessTokenHash; }
|
|
431
232
|
});
|
|
432
233
|
Object.defineProperty(exports, "cookieHeader", {
|
|
433
234
|
enumerable: true,
|
|
434
|
-
get: function () { return
|
|
235
|
+
get: function () { return chunk2XMKZWC6_cjs.cookieHeader; }
|
|
236
|
+
});
|
|
237
|
+
Object.defineProperty(exports, "createDpopKey", {
|
|
238
|
+
enumerable: true,
|
|
239
|
+
get: function () { return chunk2XMKZWC6_cjs.createDpopKey; }
|
|
240
|
+
});
|
|
241
|
+
Object.defineProperty(exports, "createDpopProof", {
|
|
242
|
+
enumerable: true,
|
|
243
|
+
get: function () { return chunk2XMKZWC6_cjs.createDpopProof; }
|
|
435
244
|
});
|
|
436
245
|
Object.defineProperty(exports, "createJwksCache", {
|
|
437
246
|
enumerable: true,
|
|
438
|
-
get: function () { return
|
|
247
|
+
get: function () { return chunk2XMKZWC6_cjs.createJwksCache; }
|
|
248
|
+
});
|
|
249
|
+
Object.defineProperty(exports, "createMemoryReplayStore", {
|
|
250
|
+
enumerable: true,
|
|
251
|
+
get: function () { return chunk2XMKZWC6_cjs.createMemoryReplayStore; }
|
|
439
252
|
});
|
|
440
253
|
Object.defineProperty(exports, "createSsoClient", {
|
|
441
254
|
enumerable: true,
|
|
442
|
-
get: function () { return
|
|
255
|
+
get: function () { return chunk2XMKZWC6_cjs.createSsoClient; }
|
|
256
|
+
});
|
|
257
|
+
Object.defineProperty(exports, "createTicketClient", {
|
|
258
|
+
enumerable: true,
|
|
259
|
+
get: function () { return chunk2XMKZWC6_cjs.createTicketClient; }
|
|
260
|
+
});
|
|
261
|
+
Object.defineProperty(exports, "exchangeUserToken", {
|
|
262
|
+
enumerable: true,
|
|
263
|
+
get: function () { return chunk2XMKZWC6_cjs.exchangeUserToken; }
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(exports, "fetchTicket", {
|
|
266
|
+
enumerable: true,
|
|
267
|
+
get: function () { return chunk2XMKZWC6_cjs.fetchTicket; }
|
|
443
268
|
});
|
|
444
269
|
Object.defineProperty(exports, "loadSsoConfig", {
|
|
445
270
|
enumerable: true,
|
|
446
|
-
get: function () { return
|
|
271
|
+
get: function () { return chunk2XMKZWC6_cjs.loadSsoConfig; }
|
|
447
272
|
});
|
|
448
273
|
Object.defineProperty(exports, "memoryTokenStore", {
|
|
449
274
|
enumerable: true,
|
|
450
|
-
get: function () { return
|
|
275
|
+
get: function () { return chunk2XMKZWC6_cjs.memoryTokenStore; }
|
|
276
|
+
});
|
|
277
|
+
Object.defineProperty(exports, "normalizeHtu", {
|
|
278
|
+
enumerable: true,
|
|
279
|
+
get: function () { return chunk2XMKZWC6_cjs.normalizeHtu; }
|
|
451
280
|
});
|
|
452
281
|
Object.defineProperty(exports, "openEmbeddedFlow", {
|
|
453
282
|
enumerable: true,
|
|
454
|
-
get: function () { return
|
|
283
|
+
get: function () { return chunk2XMKZWC6_cjs.openEmbeddedFlow; }
|
|
455
284
|
});
|
|
456
285
|
Object.defineProperty(exports, "readCookie", {
|
|
457
286
|
enumerable: true,
|
|
458
|
-
get: function () { return
|
|
287
|
+
get: function () { return chunk2XMKZWC6_cjs.readCookie; }
|
|
459
288
|
});
|
|
460
289
|
Object.defineProperty(exports, "sealEmbeddedFlow", {
|
|
461
290
|
enumerable: true,
|
|
462
|
-
get: function () { return
|
|
291
|
+
get: function () { return chunk2XMKZWC6_cjs.sealEmbeddedFlow; }
|
|
463
292
|
});
|
|
464
293
|
Object.defineProperty(exports, "signSession", {
|
|
465
294
|
enumerable: true,
|
|
466
|
-
get: function () { return
|
|
295
|
+
get: function () { return chunk2XMKZWC6_cjs.signSession; }
|
|
467
296
|
});
|
|
468
297
|
Object.defineProperty(exports, "signValue", {
|
|
469
298
|
enumerable: true,
|
|
470
|
-
get: function () { return
|
|
299
|
+
get: function () { return chunk2XMKZWC6_cjs.signValue; }
|
|
300
|
+
});
|
|
301
|
+
Object.defineProperty(exports, "verifyDpopProof", {
|
|
302
|
+
enumerable: true,
|
|
303
|
+
get: function () { return chunk2XMKZWC6_cjs.verifyDpopProof; }
|
|
471
304
|
});
|
|
472
305
|
Object.defineProperty(exports, "verifySession", {
|
|
473
306
|
enumerable: true,
|
|
474
|
-
get: function () { return
|
|
307
|
+
get: function () { return chunk2XMKZWC6_cjs.verifySession; }
|
|
475
308
|
});
|
|
476
309
|
Object.defineProperty(exports, "verifyValue", {
|
|
477
310
|
enumerable: true,
|
|
478
|
-
get: function () { return
|
|
311
|
+
get: function () { return chunk2XMKZWC6_cjs.verifyValue; }
|
|
479
312
|
});
|
|
480
|
-
exports.DEFAULT_ISSUER = DEFAULT_ISSUER;
|
|
481
313
|
exports.MAX_ACT_DEPTH = MAX_ACT_DEPTH;
|
|
482
|
-
exports.NoWorkloadIdentityError = NoWorkloadIdentityError;
|
|
483
314
|
exports.TICKET_FORMAT_VERSION = TICKET_FORMAT_VERSION;
|
|
484
|
-
exports.TicketExchangeError = TicketExchangeError;
|
|
485
|
-
exports.TicketUnavailableError = TicketUnavailableError;
|
|
486
|
-
exports.accessTokenHash = accessTokenHash;
|
|
487
|
-
exports.createDpopKey = createDpopKey;
|
|
488
|
-
exports.createDpopProof = createDpopProof;
|
|
489
|
-
exports.createMemoryReplayStore = createMemoryReplayStore;
|
|
490
|
-
exports.createTicketClient = createTicketClient;
|
|
491
315
|
exports.createTicketVerifier = createTicketVerifier;
|
|
492
|
-
exports.fetchTicket = fetchTicket;
|
|
493
|
-
exports.normalizeHtu = normalizeHtu;
|
|
494
|
-
exports.verifyDpopProof = verifyDpopProof;
|
|
495
316
|
//# sourceMappingURL=index.cjs.map
|
|
496
317
|
//# sourceMappingURL=index.cjs.map
|