@passflow/node 0.0.0-bootstrap.0 → 0.0.0-stage

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.
@@ -1,491 +0,0 @@
1
- // src/acr.ts
2
- const ACR_NONE = "0";
3
- const AAL1 = "1";
4
- const AAL2 = "2";
5
- const AAL3 = "3";
6
- const ACR_LEXICAL = /^[+-]?[0-9]+$/;
7
- const INT64_MAX = 9223372036854775807n;
8
- /**
9
- * The ordinal level of an `acr` value, by the rule the server's `strconv.Atoi` applies on a 64-bit
10
- * platform (`server_level` in the corpus): optional sign and any number of ASCII digits, the value
11
- * must fit a signed 64-bit integer; a lexical failure, an out-of-range value, a negative value or a
12
- * non-string is level 0.
13
- *
14
- * Internal. It returns `bigint` so that nothing on the decision path goes through a `Number`.
15
- */
16
- function parseACRLevel(acr) {
17
- if (typeof acr !== "string" || !ACR_LEXICAL.test(acr)) return 0n;
18
- const level = BigInt(acr);
19
- return level < 0n || level > INT64_MAX ? 0n : level;
20
- }
21
- /**
22
- * Whether a token's `acr` meets the required level. Both sides are compared as exact 64-bit integers,
23
- * and a required side that parses to level 0 is never satisfied: a wrong configuration string fails
24
- * closed here as well as at `requireACR` construction.
25
- */
26
- function acrSatisfies(acr, min) {
27
- const required = parseACRLevel(min);
28
- return required !== 0n && parseACRLevel(acr) >= required;
29
- }
30
- /**
31
- * The level as a `number`, for display and logging. It is exact only up to 2^53, and nothing in this
32
- * library decides with it: use {@link acrSatisfies} to compare.
33
- */
34
- function acrLevel(acr) {
35
- return Number(parseACRLevel(acr));
36
- }
37
- // src/bearer.ts
38
- const BEARER_PREFIX = /^bearer(?:[ \t]+|$)/i;
39
- /**
40
- * The token from an `Authorization` header. The scheme is matched case-insensitively (RFC 9110). Any
41
- * other scheme, an absent header, and a `Bearer` with an empty or whitespace-only remainder all give
42
- * `undefined`.
43
- */
44
- function extractBearer(authorization) {
45
- if (typeof authorization !== "string") return;
46
- const header = authorization.trim();
47
- const prefix = BEARER_PREFIX.exec(header);
48
- if (prefix === null) return;
49
- const token = header.slice(prefix[0].length);
50
- return token === "" ? void 0 : token;
51
- }
52
- // src/challenge.ts
53
- const MAX_AGE_ERROR = "[passflow] maxAgeSeconds must be a finite integer between 1 and Number.MAX_SAFE_INTEGER";
54
- const FORMAT_MAX_AGE_ERROR = "[passflow] maxAge must be undefined or a finite number no greater than Number.MAX_SAFE_INTEGER";
55
- const FORMAT_ACR_ERROR = "[passflow] acrValues must be undefined or a string";
56
- /**
57
- * The constructor rule for a freshness limit (`freshness.json#max_age_input`): a finite number,
58
- * truncated toward zero, at least 1 and a safe integer, or a `TypeError`. The bound means `String()`
59
- * always yields plain decimal, so a challenge can never carry `max_age=1e+21`, which the browser
60
- * SDK's `Number.parseInt` reads as 1. The returned value is both what is enforced and what the
61
- * challenge carries.
62
- */
63
- function assertMaxAge(value) {
64
- if (typeof value !== "number" || !Number.isFinite(value)) throw new TypeError(MAX_AGE_ERROR);
65
- const seconds = Math.trunc(value);
66
- if (seconds < 1 || !Number.isSafeInteger(seconds)) throw new TypeError(MAX_AGE_ERROR);
67
- return seconds;
68
- }
69
- /**
70
- * The exact RFC 9470 `WWW-Authenticate` bytes the server's `SetInsufficientAuthChallenge` emits. This
71
- * is a formatter, not a constructor: a `maxAge` that truncates to zero or below is omitted, as the
72
- * server omits it, and it does not run {@link assertMaxAge}. A non-finite number, a non-number, or a
73
- * positive value above `Number.MAX_SAFE_INTEGER` is a `TypeError`.
74
- *
75
- * `acrValues` is a space-separated list of acr tokens, inserted unescaped exactly as the server does.
76
- */
77
- function formatChallenge(c) {
78
- let header = "Bearer error=\"insufficient_user_authentication\"";
79
- if (c.acrValues !== void 0) {
80
- if (typeof c.acrValues !== "string") throw new TypeError(FORMAT_ACR_ERROR);
81
- if (c.acrValues !== "") header += `, acr_values="${c.acrValues}"`;
82
- }
83
- if (c.maxAge !== void 0) {
84
- if (typeof c.maxAge !== "number" || !Number.isFinite(c.maxAge)) throw new TypeError(FORMAT_MAX_AGE_ERROR);
85
- const seconds = Math.trunc(c.maxAge);
86
- if (seconds > 0) {
87
- if (!Number.isSafeInteger(seconds)) throw new TypeError(FORMAT_MAX_AGE_ERROR);
88
- header += `, max_age=${String(seconds)}`;
89
- }
90
- }
91
- return header;
92
- }
93
- // src/claims.ts
94
- const MAX_EXACT_SECONDS = 2 ** 53;
95
- const provenance = /* @__PURE__ */ new WeakMap();
96
- /** Internal: records that `verifier.verify` produced exactly this object. */
97
- function recordProvenance(claims, verifier) {
98
- provenance.set(claims, verifier);
99
- }
100
- /**
101
- * True only for the exact object `verifier.verify` returned. A spread or clone loses provenance, which
102
- * costs one more verification and never a bypass. So does any wrapper or decorator object that delegates
103
- * to `verifier.verify`: it is a different identity, and this verifier's adapter re-verifies claims it
104
- * returns. Two verifiers built from the same configuration are different identities too.
105
- */
106
- function verifiedBy(claims, verifier) {
107
- return provenance.get(claims) === verifier && verifier !== void 0;
108
- }
109
- /**
110
- * Internal: a numeric date within ±2^53, the rule Go's `numericDate` applies. Beyond it a JSON number is no
111
- * longer an exact count of seconds, so the claim reads as absent.
112
- */
113
- function isExactSeconds(value) {
114
- return typeof value === "number" && Math.abs(value) <= MAX_EXACT_SECONDS;
115
- }
116
- function isPlainObject(value) {
117
- return typeof value === "object" && value !== null && !Array.isArray(value);
118
- }
119
- function isStringArray(value) {
120
- return Array.isArray(value) && value.every((entry) => typeof entry === "string");
121
- }
122
- function stringsOf(value) {
123
- return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
124
- }
125
- /** A wrong JSON type means the membership cannot be read. `null` reads as absent, as Go's decoder does. */
126
- function decodeMembership(value) {
127
- if (!isPlainObject(value)) return;
128
- const { tenant_id, tenant_name, tenant_roles, root_group_id, groups, group_names } = value;
129
- const membership = { tenantId: "" };
130
- if (tenant_id !== void 0 && tenant_id !== null) {
131
- if (typeof tenant_id !== "string") return void 0;
132
- membership.tenantId = tenant_id;
133
- }
134
- if (tenant_name !== void 0 && tenant_name !== null) {
135
- if (typeof tenant_name !== "string") return void 0;
136
- membership.tenantName = tenant_name;
137
- }
138
- if (tenant_roles !== void 0 && tenant_roles !== null) {
139
- if (!isStringArray(tenant_roles)) return void 0;
140
- membership.tenantRoles = tenant_roles;
141
- }
142
- if (root_group_id !== void 0 && root_group_id !== null) {
143
- if (typeof root_group_id !== "string") return void 0;
144
- membership.rootGroupId = root_group_id;
145
- }
146
- if (groups !== void 0 && groups !== null) {
147
- if (!isPlainObject(groups)) return void 0;
148
- const entries = Object.entries(groups).filter(([, roles]) => roles !== null);
149
- if (!entries.every(([, roles]) => isStringArray(roles))) return void 0;
150
- membership.groups = Object.fromEntries(entries);
151
- }
152
- if (group_names !== void 0 && group_names !== null) {
153
- if (!isPlainObject(group_names)) return void 0;
154
- const entries = Object.entries(group_names).filter(([, name]) => name !== null);
155
- if (!entries.every(([, name]) => typeof name === "string")) return void 0;
156
- membership.groupNames = Object.fromEntries(entries);
157
- }
158
- return membership;
159
- }
160
- /** A membership that fails to decode drops that tenant only: the shape is informational, the token stays valid. */
161
- function decodeTenants(value) {
162
- if (!isPlainObject(value)) return {};
163
- const tenants = [];
164
- for (const [tenantId, raw] of Object.entries(value)) {
165
- const membership = decodeMembership(raw);
166
- if (membership !== void 0) tenants.push([tenantId, membership]);
167
- }
168
- return Object.fromEntries(tenants);
169
- }
170
- /** Fail-closed claim extraction from a payload whose signature and registered claims already passed. */
171
- function extractClaims(payload, verifiedAt) {
172
- const { sub, iss, aud, exp, iat, auth_time: authTime, acr, amr, scopes, sid, type, passflow_tm: tenants } = payload;
173
- const claims = {
174
- sub: typeof sub === "string" ? sub : "",
175
- iss: typeof iss === "string" ? iss : "",
176
- aud: typeof aud === "string" ? [aud] : stringsOf(aud),
177
- exp,
178
- acr: typeof acr === "string" ? acr : "0",
179
- amr: stringsOf(amr),
180
- scopes: stringsOf(scopes),
181
- type: typeof type === "string" ? type : "",
182
- tenants: decodeTenants(tenants),
183
- verifiedAt,
184
- raw: payload
185
- };
186
- if (isExactSeconds(iat)) claims.iat = iat;
187
- if (isExactSeconds(authTime)) claims.authTime = Math.trunc(authTime);
188
- if (typeof sid === "string") claims.sid = sid;
189
- return claims;
190
- }
191
- /**
192
- * The roles a user holds in a tenant: `groups[rootGroupId]`, the rule the server's `CalcTenantRoles` and
193
- * `@passflow/core`'s `parseMembership` apply. A missing tenant, root group or map gives an empty list.
194
- * So does an empty `rootGroupId`, unlike the server: no role is granted from a group keyed by "".
195
- * `tenantRoles` is a copy the server derives from the same root group, and is not consulted.
196
- */
197
- function rolesOf(claims, tenantId) {
198
- const { tenants } = claims;
199
- if (!isPlainObject(tenants) || !Object.hasOwn(tenants, tenantId)) return [];
200
- const { groups, rootGroupId } = tenants[tenantId];
201
- if (!isPlainObject(groups) || !rootGroupId || !Object.hasOwn(groups, rootGroupId)) return [];
202
- return [...groups[rootGroupId]];
203
- }
204
- // src/cors.ts
205
- const CHALLENGE_HEADER = "WWW-Authenticate";
206
- const CORS_EXPOSED_HEADERS = Object.freeze([CHALLENGE_HEADER]);
207
- /**
208
- * Appends `WWW-Authenticate` to an expose list unless it is already there, compared case-insensitively.
209
- * Everything else is kept as given, `*` and duplicates included: `*` is not a wildcard on a
210
- * credentialed request, so the explicit entry is what matters. This guarantees exactly one thing, that
211
- * the header appears as an explicit entry.
212
- *
213
- * Internal. Each adapter wraps it under the option name its CORS middleware uses.
214
- */
215
- function withChallengeHeader(existing) {
216
- const entries = typeof existing === "string" ? existing.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "") : [...existing ?? []];
217
- return entries.some((entry) => entry.toLowerCase() === "WWW-Authenticate".toLowerCase()) ? entries : [...entries, CHALLENGE_HEADER];
218
- }
219
- // src/errors.ts
220
- const MESSAGES = {
221
- missing_token: "[passflow] no bearer token presented",
222
- invalid_token: "[passflow] invalid token",
223
- jwks_unavailable: "[passflow] key set unavailable"
224
- };
225
- /**
226
- * An authentication failure. The message is fixed per code and carries nothing from the token, the
227
- * request or the JWKS URL. A jose error is never attached as `cause`: jose's claim errors keep the
228
- * whole payload on `.payload`.
229
- */
230
- var PassflowAuthError = class extends Error {
231
- code;
232
- reason;
233
- status;
234
- constructor(code, reason, options) {
235
- super(reason === void 0 ? MESSAGES[code] : `${MESSAGES[code]}: ${reason}`, options);
236
- this.name = "PassflowAuthError";
237
- this.code = code;
238
- this.status = code === "jwks_unavailable" ? 503 : 401;
239
- if (reason !== void 0) this.reason = reason;
240
- }
241
- };
242
- /**
243
- * A programming error, such as reading the claims before any middleware ran. It is deliberately not
244
- * a `PassflowAuthError`: those mean 401/503, which the browser SDK acts on, and this must reach the
245
- * framework's error handling as a 500.
246
- */
247
- var PassflowUsageError = class extends Error {
248
- constructor(message) {
249
- super(message);
250
- this.name = "PassflowUsageError";
251
- }
252
- };
253
- /**
254
- * True for a `PassflowAuthError`, including one from the other copy of this package when the ESM
255
- * and CJS builds are both loaded, where `instanceof` alone would say no.
256
- */
257
- function isPassflowAuthError(e) {
258
- if (e instanceof PassflowAuthError) return true;
259
- if (!(e instanceof Error) || e.name !== "PassflowAuthError") return false;
260
- const { code } = e;
261
- return code === "missing_token" || code === "invalid_token" || code === "jwks_unavailable";
262
- }
263
- // src/evaluate.ts
264
- const CACHE_CONTROL = "Cache-Control";
265
- const NO_STORE = "no-store";
266
- const reject = (status, wwwAuthenticate) => ({
267
- kind: "reject",
268
- status,
269
- headers: wwwAuthenticate === void 0 ? { [CACHE_CONTROL]: NO_STORE } : {
270
- [CHALLENGE_HEADER]: wwwAuthenticate,
271
- [CACHE_CONTROL]: NO_STORE
272
- }
273
- });
274
- /**
275
- * Authentication failures never carry the step-up error: the browser SDK acts only on the step-up challenge,
276
- * and every other response, a plain 401 or a 503 included, reaches the caller's code unchanged.
277
- */
278
- function rejectAuthentication(code) {
279
- switch (code) {
280
- case "missing_token": return reject(401, "Bearer");
281
- case "invalid_token": return reject(401, "Bearer error=\"invalid_token\"");
282
- case "jwks_unavailable": return reject(503);
283
- }
284
- }
285
- /**
286
- * Validates a requirement and returns it with the effective freshness limit. Throws `TypeError`: this is a
287
- * programming error that should stop the process at route registration, not become a `Decision`.
288
- *
289
- * Internal: `requireACR` and `requireFresh` call it at construction.
290
- */
291
- function assertRequirement(requirement) {
292
- if (typeof requirement === "object" && requirement !== null) {
293
- if (requirement.kind === "acr") {
294
- if (parseACRLevel(requirement.min) === 0n) throw new TypeError("[passflow] the required ACR must parse to a level above 0");
295
- return requirement;
296
- }
297
- if (requirement.kind === "fresh") return {
298
- kind: "fresh",
299
- maxAgeSeconds: assertMaxAge(requirement.maxAgeSeconds)
300
- };
301
- }
302
- throw new TypeError("[passflow] a requirement is { kind: \"acr\", min } or { kind: \"fresh\", maxAgeSeconds }");
303
- }
304
- function isFresh(claims, maxAgeSeconds) {
305
- const { authTime, verifiedAt } = claims;
306
- if (!isExactSeconds(authTime)) return false;
307
- return (typeof verifiedAt === "number" && Number.isFinite(verifiedAt) && verifiedAt > 0 ? Math.floor(verifiedAt) : Math.floor(Date.now() / 1e3)) - Math.trunc(authTime) <= maxAgeSeconds;
308
- }
309
- /**
310
- * Decides one requirement against claims. No claims means the middleware was composed wrongly, so the answer
311
- * is a 500 with no challenge: never a step-up, which the SDK would try to satisfy, and never a 401, because a
312
- * wiring bug must not be reported as a bad token. Throws `TypeError` on an invalid requirement.
313
- */
314
- function evaluate(claims, requirement) {
315
- const checked = assertRequirement(requirement);
316
- if (claims === void 0 || claims === null) return reject(500);
317
- if (checked.kind === "acr") return acrSatisfies(claims.acr, checked.min) ? { kind: "allow" } : reject(401, formatChallenge({ acrValues: checked.min }));
318
- return isFresh(claims, checked.maxAgeSeconds) ? { kind: "allow" } : reject(401, formatChallenge({ maxAge: checked.maxAgeSeconds }));
319
- }
320
- /**
321
- * Authenticates a request. `existing` claims are reused only when `verifier` produced that exact object;
322
- * otherwise the presented header is verified with `verifier`, so a token outside this verifier's trust policy
323
- * is rejected as not valid here, never as insufficient. Never rejects: a failure is a `{ reject }` value.
324
- */
325
- async function authenticate(verifier, authorization, existing) {
326
- if (existing !== void 0 && existing !== null && verifiedBy(existing, verifier)) return { claims: existing };
327
- const token = extractBearer(authorization);
328
- if (token === void 0) return { reject: rejectAuthentication("missing_token") };
329
- try {
330
- return { claims: await verifier.verify(token) };
331
- } catch (error) {
332
- return { reject: isPassflowAuthError(error) ? rejectAuthentication(error.code) : reject(500) };
333
- }
334
- }
335
- /**
336
- * Internal: one adapter step. Authenticates, then applies the requirement if there is one.
337
- */
338
- async function guard(verifier, authorization, existing, requirement) {
339
- const result = await authenticate(verifier, authorization, existing);
340
- if ("reject" in result || requirement === void 0) return result;
341
- const decision = evaluate(result.claims, requirement);
342
- return decision.kind === "reject" ? { reject: decision } : result;
343
- }
344
- /** Internal: the adapters fail at construction when handed something that cannot verify. */
345
- function assertVerifier(verifier) {
346
- if (typeof verifier !== "object" || verifier === null || typeof verifier.verify !== "function") throw new TypeError("[passflow] an adapter needs a verifier from createVerifier");
347
- }
348
- Object.defineProperty(exports, "AAL1", {
349
- enumerable: true,
350
- get: function() {
351
- return AAL1;
352
- }
353
- });
354
- Object.defineProperty(exports, "AAL2", {
355
- enumerable: true,
356
- get: function() {
357
- return AAL2;
358
- }
359
- });
360
- Object.defineProperty(exports, "AAL3", {
361
- enumerable: true,
362
- get: function() {
363
- return AAL3;
364
- }
365
- });
366
- Object.defineProperty(exports, "ACR_NONE", {
367
- enumerable: true,
368
- get: function() {
369
- return ACR_NONE;
370
- }
371
- });
372
- Object.defineProperty(exports, "CHALLENGE_HEADER", {
373
- enumerable: true,
374
- get: function() {
375
- return CHALLENGE_HEADER;
376
- }
377
- });
378
- Object.defineProperty(exports, "CORS_EXPOSED_HEADERS", {
379
- enumerable: true,
380
- get: function() {
381
- return CORS_EXPOSED_HEADERS;
382
- }
383
- });
384
- Object.defineProperty(exports, "PassflowAuthError", {
385
- enumerable: true,
386
- get: function() {
387
- return PassflowAuthError;
388
- }
389
- });
390
- Object.defineProperty(exports, "PassflowUsageError", {
391
- enumerable: true,
392
- get: function() {
393
- return PassflowUsageError;
394
- }
395
- });
396
- Object.defineProperty(exports, "acrLevel", {
397
- enumerable: true,
398
- get: function() {
399
- return acrLevel;
400
- }
401
- });
402
- Object.defineProperty(exports, "acrSatisfies", {
403
- enumerable: true,
404
- get: function() {
405
- return acrSatisfies;
406
- }
407
- });
408
- Object.defineProperty(exports, "assertMaxAge", {
409
- enumerable: true,
410
- get: function() {
411
- return assertMaxAge;
412
- }
413
- });
414
- Object.defineProperty(exports, "assertRequirement", {
415
- enumerable: true,
416
- get: function() {
417
- return assertRequirement;
418
- }
419
- });
420
- Object.defineProperty(exports, "assertVerifier", {
421
- enumerable: true,
422
- get: function() {
423
- return assertVerifier;
424
- }
425
- });
426
- Object.defineProperty(exports, "authenticate", {
427
- enumerable: true,
428
- get: function() {
429
- return authenticate;
430
- }
431
- });
432
- Object.defineProperty(exports, "evaluate", {
433
- enumerable: true,
434
- get: function() {
435
- return evaluate;
436
- }
437
- });
438
- Object.defineProperty(exports, "extractBearer", {
439
- enumerable: true,
440
- get: function() {
441
- return extractBearer;
442
- }
443
- });
444
- Object.defineProperty(exports, "extractClaims", {
445
- enumerable: true,
446
- get: function() {
447
- return extractClaims;
448
- }
449
- });
450
- Object.defineProperty(exports, "formatChallenge", {
451
- enumerable: true,
452
- get: function() {
453
- return formatChallenge;
454
- }
455
- });
456
- Object.defineProperty(exports, "guard", {
457
- enumerable: true,
458
- get: function() {
459
- return guard;
460
- }
461
- });
462
- Object.defineProperty(exports, "isPassflowAuthError", {
463
- enumerable: true,
464
- get: function() {
465
- return isPassflowAuthError;
466
- }
467
- });
468
- Object.defineProperty(exports, "recordProvenance", {
469
- enumerable: true,
470
- get: function() {
471
- return recordProvenance;
472
- }
473
- });
474
- Object.defineProperty(exports, "rolesOf", {
475
- enumerable: true,
476
- get: function() {
477
- return rolesOf;
478
- }
479
- });
480
- Object.defineProperty(exports, "verifiedBy", {
481
- enumerable: true,
482
- get: function() {
483
- return verifiedBy;
484
- }
485
- });
486
- Object.defineProperty(exports, "withChallengeHeader", {
487
- enumerable: true,
488
- get: function() {
489
- return withChallengeHeader;
490
- }
491
- });
package/dist/express.cjs DELETED
@@ -1,52 +0,0 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_evaluate = require("./evaluate-C20MecTf.cjs");
3
- // src/express.ts
4
- /** Written directly and never through `next(err)`: a custom error handler would drop `WWW-Authenticate`. */
5
- function send(res, decision) {
6
- if (decision.kind === "reject") res.status(decision.status).set(decision.headers).end();
7
- }
8
- /**
9
- * Express 4 and 5 middleware. `authenticate` always verifies the presented token and replaces any claims on the
10
- * request. `requireACR` and `requireFresh` work alone: they reuse claims only when this verifier produced that
11
- * exact object, and otherwise verify the presented token themselves. Both throw `TypeError` at construction on
12
- * an invalid level or limit.
13
- */
14
- function passflowExpress(verifier) {
15
- require_evaluate.assertVerifier(verifier);
16
- const middleware = (reuse, requirement) => (req, res, next) => {
17
- require_evaluate.guard(verifier, req.headers.authorization, reuse ? req.passflow : void 0, requirement).then((result) => {
18
- if ("reject" in result) {
19
- send(res, result.reject);
20
- return;
21
- }
22
- req.passflow = result.claims;
23
- next();
24
- }).catch(next);
25
- };
26
- return {
27
- authenticate: middleware(false),
28
- requireACR: (min) => middleware(true, require_evaluate.assertRequirement({
29
- kind: "acr",
30
- min
31
- })),
32
- requireFresh: (maxAgeSeconds) => middleware(true, require_evaluate.assertRequirement({
33
- kind: "fresh",
34
- maxAgeSeconds
35
- }))
36
- };
37
- }
38
- /** The claims a Passflow middleware put on this request. Throws `PassflowUsageError` if none ran. */
39
- function getAuth(req) {
40
- if (req.passflow === void 0 || req.passflow === null) throw new require_evaluate.PassflowUsageError("[passflow] getAuth called before a Passflow middleware ran on this request");
41
- return req.passflow;
42
- }
43
- /** Names `WWW-Authenticate` in the `cors` package's `exposedHeaders`, keeping what is already there. */
44
- function exposeChallengeHeader(cors) {
45
- return {
46
- ...cors,
47
- exposedHeaders: require_evaluate.withChallengeHeader(cors?.exposedHeaders)
48
- };
49
- }
50
- exports.exposeChallengeHeader = exposeChallengeHeader;
51
- exports.getAuth = getAuth;
52
- exports.passflowExpress = passflowExpress;
@@ -1,29 +0,0 @@
1
- import { r as Verifier, t as PassflowClaims } from "./claims-BHJhnzch.cjs";
2
- import { Request, RequestHandler } from "express";
3
- declare global {
4
- namespace Express {
5
- interface Request {
6
- /** `req.passflow`, not `req.auth`: a second global `auth` type collides with express-jwt and Auth0. */
7
- passflow?: PassflowClaims;
8
- }
9
- }
10
- }
11
- /**
12
- * Express 4 and 5 middleware. `authenticate` always verifies the presented token and replaces any claims on the
13
- * request. `requireACR` and `requireFresh` work alone: they reuse claims only when this verifier produced that
14
- * exact object, and otherwise verify the presented token themselves. Both throw `TypeError` at construction on
15
- * an invalid level or limit.
16
- */
17
- export declare function passflowExpress(verifier: Verifier): {
18
- authenticate: RequestHandler;
19
- requireACR(min: string): RequestHandler;
20
- requireFresh(maxAgeSeconds: number): RequestHandler;
21
- };
22
- /** The claims a Passflow middleware put on this request. Throws `PassflowUsageError` if none ran. */
23
- export declare function getAuth(req: Pick<Request, 'passflow'>): PassflowClaims;
24
- /** Names `WWW-Authenticate` in the `cors` package's `exposedHeaders`, keeping what is already there. */
25
- export declare function exposeChallengeHeader<T extends object>(cors: T & {
26
- exposedHeaders?: string | string[];
27
- }): Omit<T, 'exposedHeaders'> & {
28
- exposedHeaders: string[];
29
- };
@@ -1,29 +0,0 @@
1
- import { r as Verifier, t as PassflowClaims } from "./claims-BHJhnzch.mjs";
2
- import { Request, RequestHandler } from "express";
3
- declare global {
4
- namespace Express {
5
- interface Request {
6
- /** `req.passflow`, not `req.auth`: a second global `auth` type collides with express-jwt and Auth0. */
7
- passflow?: PassflowClaims;
8
- }
9
- }
10
- }
11
- /**
12
- * Express 4 and 5 middleware. `authenticate` always verifies the presented token and replaces any claims on the
13
- * request. `requireACR` and `requireFresh` work alone: they reuse claims only when this verifier produced that
14
- * exact object, and otherwise verify the presented token themselves. Both throw `TypeError` at construction on
15
- * an invalid level or limit.
16
- */
17
- export declare function passflowExpress(verifier: Verifier): {
18
- authenticate: RequestHandler;
19
- requireACR(min: string): RequestHandler;
20
- requireFresh(maxAgeSeconds: number): RequestHandler;
21
- };
22
- /** The claims a Passflow middleware put on this request. Throws `PassflowUsageError` if none ran. */
23
- export declare function getAuth(req: Pick<Request, 'passflow'>): PassflowClaims;
24
- /** Names `WWW-Authenticate` in the `cors` package's `exposedHeaders`, keeping what is already there. */
25
- export declare function exposeChallengeHeader<T extends object>(cors: T & {
26
- exposedHeaders?: string | string[];
27
- }): Omit<T, 'exposedHeaders'> & {
28
- exposedHeaders: string[];
29
- };
package/dist/express.mjs DELETED
@@ -1,49 +0,0 @@
1
- import { a as guard, d as withChallengeHeader, n as assertVerifier, s as PassflowUsageError, t as assertRequirement } from "./evaluate-BTuol-Oa.mjs";
2
- // src/express.ts
3
- /** Written directly and never through `next(err)`: a custom error handler would drop `WWW-Authenticate`. */
4
- function send(res, decision) {
5
- if (decision.kind === "reject") res.status(decision.status).set(decision.headers).end();
6
- }
7
- /**
8
- * Express 4 and 5 middleware. `authenticate` always verifies the presented token and replaces any claims on the
9
- * request. `requireACR` and `requireFresh` work alone: they reuse claims only when this verifier produced that
10
- * exact object, and otherwise verify the presented token themselves. Both throw `TypeError` at construction on
11
- * an invalid level or limit.
12
- */
13
- function passflowExpress(verifier) {
14
- assertVerifier(verifier);
15
- const middleware = (reuse, requirement) => (req, res, next) => {
16
- guard(verifier, req.headers.authorization, reuse ? req.passflow : void 0, requirement).then((result) => {
17
- if ("reject" in result) {
18
- send(res, result.reject);
19
- return;
20
- }
21
- req.passflow = result.claims;
22
- next();
23
- }).catch(next);
24
- };
25
- return {
26
- authenticate: middleware(false),
27
- requireACR: (min) => middleware(true, assertRequirement({
28
- kind: "acr",
29
- min
30
- })),
31
- requireFresh: (maxAgeSeconds) => middleware(true, assertRequirement({
32
- kind: "fresh",
33
- maxAgeSeconds
34
- }))
35
- };
36
- }
37
- /** The claims a Passflow middleware put on this request. Throws `PassflowUsageError` if none ran. */
38
- function getAuth(req) {
39
- if (req.passflow === void 0 || req.passflow === null) throw new PassflowUsageError("[passflow] getAuth called before a Passflow middleware ran on this request");
40
- return req.passflow;
41
- }
42
- /** Names `WWW-Authenticate` in the `cors` package's `exposedHeaders`, keeping what is already there. */
43
- function exposeChallengeHeader(cors) {
44
- return {
45
- ...cors,
46
- exposedHeaders: withChallengeHeader(cors?.exposedHeaders)
47
- };
48
- }
49
- export { exposeChallengeHeader, getAuth, passflowExpress };