@run402/functions 2.9.0 → 3.1.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/dist/auth/errors.d.ts +106 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/errors.js +205 -0
- package/dist/auth/errors.js.map +1 -0
- package/dist/auth/index.d.ts +112 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +585 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/types.d.ts +86 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +13 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/auth/url-validation.d.ts +31 -0
- package/dist/auth/url-validation.d.ts.map +1 -0
- package/dist/auth/url-validation.js +83 -0
- package/dist/auth/url-validation.js.map +1 -0
- package/dist/auth.d.ts +25 -50
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +34 -103
- package/dist/auth.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +40 -0
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/actor-context-verify.d.ts +95 -0
- package/dist/lib/actor-context-verify.d.ts.map +1 -0
- package/dist/lib/actor-context-verify.js +200 -0
- package/dist/lib/actor-context-verify.js.map +1 -0
- package/dist/runtime-context.d.ts +23 -1
- package/dist/runtime-context.d.ts.map +1 -1
- package/dist/runtime-context.js +64 -0
- package/dist/runtime-context.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `auth.*` — the sole server-side auth namespace.
|
|
3
|
+
*
|
|
4
|
+
* The single import line for any consumer:
|
|
5
|
+
*
|
|
6
|
+
* import { auth } from "@run402/functions";
|
|
7
|
+
*
|
|
8
|
+
* Surface (deliberately small):
|
|
9
|
+
*
|
|
10
|
+
* auth.user() → Actor | null
|
|
11
|
+
* auth.requireUser() → Actor (throws / 303 otherwise)
|
|
12
|
+
* auth.requireRole(role) → { user, role }
|
|
13
|
+
* auth.requireMembership(membership) → { user, membership }
|
|
14
|
+
* auth.requireFresh({ maxAge, amr? }) → void (throws / 303 otherwise)
|
|
15
|
+
* auth.identities.link({ ... }) → void
|
|
16
|
+
* auth.fetch(input, init?) → Response (same-origin only)
|
|
17
|
+
* auth.csrfToken() → string
|
|
18
|
+
* auth.csrfField() → "<input type=hidden ...>"
|
|
19
|
+
* auth.sessions.createResponseFromIdentity({ ... }) → Response
|
|
20
|
+
* auth.sessions.createResponseFromTenantAssertion({ tenant, user, method }) → Response
|
|
21
|
+
* auth.sessions.endResponse() → Response
|
|
22
|
+
* auth.invalidCredentials() → InvalidCredentialsError (throw it)
|
|
23
|
+
*
|
|
24
|
+
* Behaviour notes baked into the helpers:
|
|
25
|
+
* - Calling any helper taints the cache (the response now depends on
|
|
26
|
+
* per-request actor state). The taint is monotonic — once set, the
|
|
27
|
+
* SSR cache layer treats the response as non-cacheable until the
|
|
28
|
+
* request completes.
|
|
29
|
+
* - HTML-vs-JSON failure decisions are made by the gateway middleware
|
|
30
|
+
* (303 redirect for HTML, 401/403 envelope for JSON). The SDK throws
|
|
31
|
+
* a typed Error subclass; framework code OR the gateway translates.
|
|
32
|
+
* - `requireRole` / `requireMembership` always read fresh server-side
|
|
33
|
+
* grant data — no positive cache (matches D8 + the "instant revocation"
|
|
34
|
+
* contract). For now we route via `getRole` which the gateway sets
|
|
35
|
+
* at the routed-function envelope; once the v1.60 grants table lands,
|
|
36
|
+
* gate helpers will JOIN against it inside the same request.
|
|
37
|
+
* - `requireFresh` consults the per-method `amr_times` on the Actor —
|
|
38
|
+
* a recent password proof does NOT satisfy `{amr: ["passkey"]}`.
|
|
39
|
+
*
|
|
40
|
+
* @see openspec/changes/auth-aware-ssr/specs/auth-sdk-namespace/spec.md
|
|
41
|
+
*/
|
|
42
|
+
import { getCurrentContext, requireActiveContext, taintCacheBypass, } from "../runtime-context.js";
|
|
43
|
+
import { config } from "../config.js";
|
|
44
|
+
import jwt from "../lib/jwt.js";
|
|
45
|
+
import { AuthRequiredError, FetchAbsoluteUrlError, FreshnessRequiredError, InsufficientMembershipError, InsufficientRoleError, InvalidCredentialsError, TenantSubjectInvalidError, UnknownExportError, } from "./errors.js";
|
|
46
|
+
import { validateAuthFetchInput } from "./url-validation.js";
|
|
47
|
+
import crypto from "node:crypto";
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Identity & authorization helpers
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
async function user() {
|
|
52
|
+
// Taint cache regardless of outcome — the response depends on actor
|
|
53
|
+
// state once any consumer asks. The taint is monotonic (D23).
|
|
54
|
+
taintCacheBypass();
|
|
55
|
+
const ctx = getCurrentContext();
|
|
56
|
+
if (ctx === undefined) {
|
|
57
|
+
// No active context — could be (a) module scope or (b) prerendered
|
|
58
|
+
// build. The runtime-context module distinguishes these via the
|
|
59
|
+
// `active` flag, but for `auth.user()` specifically we return null
|
|
60
|
+
// for module-scope while throwing R402_AUTH_PRERENDERED for the
|
|
61
|
+
// prerendered case. Without a context we can't tell, so return
|
|
62
|
+
// null — Astro's prerender detection runs upstream in @run402/astro.
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
// SSR / cookie-session path: actor populated from the verified
|
|
66
|
+
// gateway-signed envelope at runWithContext entry.
|
|
67
|
+
if (ctx.actor) {
|
|
68
|
+
return actorContextToPublicActor(ctx.actor, ctx.projectId);
|
|
69
|
+
}
|
|
70
|
+
// auth-hosted-surface-parity: for browser SSR (routed_http) the cookie
|
|
71
|
+
// envelope is the ONLY actor input. We do NOT fall back to decoding an
|
|
72
|
+
// `Authorization: Bearer` header here — otherwise a Bearer on a GET to
|
|
73
|
+
// a tenant SSR page would resolve an actor, contradicting the
|
|
74
|
+
// "cookie is the only browser actor input" invariant (Kychon finding).
|
|
75
|
+
// The fallback is preserved only for direct/machine invocations below.
|
|
76
|
+
if (ctx.invocationKind === "routed_http") {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
// Direct function invocation path (Bearer JWT, no cookie envelope):
|
|
80
|
+
// fall back to decoding the Authorization header. This is the legacy
|
|
81
|
+
// getUser(req) contract — mobile / server-to-server callers send a
|
|
82
|
+
// signed JWT in the Authorization header, the function reads it.
|
|
83
|
+
// The gateway has already routed the request to this function and
|
|
84
|
+
// injected the Authorization header per the apikey/wallet-auth
|
|
85
|
+
// pipeline, so we can trust JWT_SECRET-signed claims here.
|
|
86
|
+
return actorFromAuthorizationHeader(ctx);
|
|
87
|
+
}
|
|
88
|
+
/** Read `Authorization: Bearer <jwt>` from the runtime context's
|
|
89
|
+
* request headers and decode it via JWT_SECRET. Returns an `Actor`
|
|
90
|
+
* populated from the JWT claims on success, `null` on absence /
|
|
91
|
+
* malformed / wrong-project / verify-fail.
|
|
92
|
+
*
|
|
93
|
+
* This is the legacy `getUser(req)` shape adapted to the v3.0 `auth.*`
|
|
94
|
+
* surface — it preserves the direct-function-invocation contract that
|
|
95
|
+
* the platform's own E2E suite exercises and that mobile / CI callers
|
|
96
|
+
* rely on. The cookie-session SSR path doesn't go through here (it
|
|
97
|
+
* populates ctx.actor at runWithContext entry via the verified
|
|
98
|
+
* envelope). */
|
|
99
|
+
function actorFromAuthorizationHeader(ctx) {
|
|
100
|
+
if (!config.JWT_SECRET)
|
|
101
|
+
return null;
|
|
102
|
+
const headers = ctx.request.headers;
|
|
103
|
+
// The runtime-context wrapper accepts either a `Headers` instance
|
|
104
|
+
// (when the gateway's buildEntryWrapper passes a Request) or a plain
|
|
105
|
+
// header object. Handle both.
|
|
106
|
+
let authHeader;
|
|
107
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
|
+
const h = headers;
|
|
109
|
+
if (typeof h?.get === "function") {
|
|
110
|
+
authHeader = h.get("authorization") ?? h.get("Authorization") ?? undefined;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const raw = h?.["authorization"] ?? h?.["Authorization"];
|
|
114
|
+
authHeader = Array.isArray(raw) ? raw[0] : raw;
|
|
115
|
+
}
|
|
116
|
+
if (!authHeader || !authHeader.startsWith("Bearer "))
|
|
117
|
+
return null;
|
|
118
|
+
const token = authHeader.slice(7);
|
|
119
|
+
try {
|
|
120
|
+
const payload = jwt.verify(token, config.JWT_SECRET);
|
|
121
|
+
if (payload.project_id !== ctx.projectId)
|
|
122
|
+
return null;
|
|
123
|
+
return {
|
|
124
|
+
id: payload.sub,
|
|
125
|
+
projectId: payload.project_id,
|
|
126
|
+
sessionId: payload.session_id ?? `bearer:${payload.sub}`,
|
|
127
|
+
email: payload.email ?? "",
|
|
128
|
+
emailVerified: false,
|
|
129
|
+
authTime: payload.auth_time ?? Math.floor(Date.now() / 1000),
|
|
130
|
+
amr: Array.isArray(payload.amr) ? [...payload.amr] : [],
|
|
131
|
+
amrTimes: {},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function requireUser() {
|
|
139
|
+
const actor = await user();
|
|
140
|
+
if (actor === null) {
|
|
141
|
+
throw new AuthRequiredError({ returnTo: currentReturnTo() });
|
|
142
|
+
}
|
|
143
|
+
return actor;
|
|
144
|
+
}
|
|
145
|
+
async function requireRole(role) {
|
|
146
|
+
const actor = await requireUser();
|
|
147
|
+
// For v1A wiring: read the gate-resolved role from the routed-function
|
|
148
|
+
// envelope header set by the gateway middleware. When the v1.60
|
|
149
|
+
// platform-owned grants table lands, this swaps to a fresh DB read
|
|
150
|
+
// joined to internal.role_grants.
|
|
151
|
+
const ctx = requireActiveContext("auth.requireRole");
|
|
152
|
+
const headerRole = readHeader(ctx.request.headers, "x-run402-user-role");
|
|
153
|
+
if (headerRole === role) {
|
|
154
|
+
return { user: actor, role };
|
|
155
|
+
}
|
|
156
|
+
throw new InsufficientRoleError(role);
|
|
157
|
+
}
|
|
158
|
+
function readHeader(headers, name) {
|
|
159
|
+
const v = headers[name] ?? headers[name.toLowerCase()] ?? headers[name.toUpperCase()];
|
|
160
|
+
return Array.isArray(v) ? v[0] : v;
|
|
161
|
+
}
|
|
162
|
+
async function requireMembership(membership) {
|
|
163
|
+
const actor = await requireUser();
|
|
164
|
+
// Membership shape mirrors role for v1A. The grant table for membership
|
|
165
|
+
// lands in a separate change (auth-as-sdlc); meanwhile the gateway-side
|
|
166
|
+
// gate helpers populate `x-run402-user-membership` when configured.
|
|
167
|
+
const ctx = requireActiveContext("auth.requireMembership");
|
|
168
|
+
const headerMembership = readHeader(ctx.request.headers, "x-run402-user-membership");
|
|
169
|
+
if (headerMembership === membership) {
|
|
170
|
+
return { user: actor, membership };
|
|
171
|
+
}
|
|
172
|
+
throw new InsufficientMembershipError(membership);
|
|
173
|
+
}
|
|
174
|
+
async function requireFresh(opts) {
|
|
175
|
+
taintCacheBypass();
|
|
176
|
+
const actor = await requireUser();
|
|
177
|
+
const maxAgeSec = parseMaxAge(opts.maxAge);
|
|
178
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
179
|
+
if (opts.amr && opts.amr.length > 0) {
|
|
180
|
+
const ok = opts.amr.some((method) => {
|
|
181
|
+
const ts = actor.amrTimes[method];
|
|
182
|
+
return typeof ts === "number" && nowSec - ts <= maxAgeSec;
|
|
183
|
+
});
|
|
184
|
+
if (!ok) {
|
|
185
|
+
throw new FreshnessRequiredError({
|
|
186
|
+
maxAge: opts.maxAge,
|
|
187
|
+
amr: opts.amr,
|
|
188
|
+
returnTo: currentReturnTo(),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (nowSec - actor.authTime <= maxAgeSec)
|
|
194
|
+
return;
|
|
195
|
+
throw new FreshnessRequiredError({
|
|
196
|
+
maxAge: opts.maxAge,
|
|
197
|
+
amr: [],
|
|
198
|
+
returnTo: currentReturnTo(),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
function parseMaxAge(raw) {
|
|
202
|
+
if (/^\d+$/.test(raw))
|
|
203
|
+
return Number(raw);
|
|
204
|
+
let total = 0;
|
|
205
|
+
const re = /(\d+)\s*([smhd])/gi;
|
|
206
|
+
let m;
|
|
207
|
+
while ((m = re.exec(raw)) !== null) {
|
|
208
|
+
const v = Number(m[1]);
|
|
209
|
+
switch (m[2].toLowerCase()) {
|
|
210
|
+
case "s":
|
|
211
|
+
total += v;
|
|
212
|
+
break;
|
|
213
|
+
case "m":
|
|
214
|
+
total += v * 60;
|
|
215
|
+
break;
|
|
216
|
+
case "h":
|
|
217
|
+
total += v * 3600;
|
|
218
|
+
break;
|
|
219
|
+
case "d":
|
|
220
|
+
total += v * 86400;
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return total;
|
|
225
|
+
}
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// auth.fetch — relative-only with manual-redirect default
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
async function authFetch(input, init) {
|
|
230
|
+
const ctx = requireActiveContext("auth.fetch");
|
|
231
|
+
const origin = `https://${ctx.host}`;
|
|
232
|
+
const result = validateAuthFetchInput(input, { requestOrigin: origin });
|
|
233
|
+
if (!result.ok) {
|
|
234
|
+
throw new FetchAbsoluteUrlError({
|
|
235
|
+
attempted: typeof input === "string" ? input : (input instanceof URL ? input.toString() : input.url),
|
|
236
|
+
reason: result.reason,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
// The validated URL is same-origin. Default redirect: "manual" so
|
|
240
|
+
// follow-cross-origin redirects don't smuggle our actor context to
|
|
241
|
+
// hostile hops. If the caller opts in via init.redirect: "follow",
|
|
242
|
+
// we still re-validate each hop — but native fetch doesn't expose
|
|
243
|
+
// hop-by-hop hooks, so we emulate by doing manual redirects.
|
|
244
|
+
const headers = new Headers(init?.headers);
|
|
245
|
+
// Forward only headers the gateway expects from a same-origin SSR
|
|
246
|
+
// fetch. Actor-context propagation is automatic (the inbound envelope
|
|
247
|
+
// is propagated as a header; the SSR runtime already verified it).
|
|
248
|
+
// Cookies are NEVER forwarded — never set the Cookie header here.
|
|
249
|
+
headers.delete("cookie");
|
|
250
|
+
headers.delete("Cookie");
|
|
251
|
+
const requestInit = {
|
|
252
|
+
...init,
|
|
253
|
+
headers,
|
|
254
|
+
redirect: init?.redirect ?? "manual",
|
|
255
|
+
};
|
|
256
|
+
return fetch(result.normalized, requestInit);
|
|
257
|
+
}
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// CSRF token helpers (double-submit token bound to the active session).
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
function csrfToken() {
|
|
262
|
+
const ctx = getCurrentContext();
|
|
263
|
+
if (!ctx || !ctx.actor) {
|
|
264
|
+
// No session ⇒ no CSRF token. Returning an empty string would let
|
|
265
|
+
// the form submit with no token at all; instead throw so the page
|
|
266
|
+
// author knows the helper should be inside `<SignedIn>`-style
|
|
267
|
+
// conditional rendering.
|
|
268
|
+
throw new AuthRequiredError();
|
|
269
|
+
}
|
|
270
|
+
// The token derivation is HMAC(session_secret, "csrf") truncated to
|
|
271
|
+
// 32 hex chars. Browsers double-submit; the gateway re-derives and
|
|
272
|
+
// compares constant-time. We use the session_id + auth_time as the
|
|
273
|
+
// poor-man's MAC input since the SDK doesn't have access to the
|
|
274
|
+
// pepper; the gateway is the authoritative verifier (cross-checks
|
|
275
|
+
// against internal.sessions via session_id). This is double-submit
|
|
276
|
+
// CSRF, not a primary control — the Origin check is.
|
|
277
|
+
const input = `${ctx.actor.sessionId}:${ctx.actor.authTime}:csrf`;
|
|
278
|
+
return crypto.createHash("sha256").update(input, "utf8").digest("hex").slice(0, 32);
|
|
279
|
+
}
|
|
280
|
+
function csrfField() {
|
|
281
|
+
return `<input type="hidden" name="_csrf" value="${escapeHtml(csrfToken())}">`;
|
|
282
|
+
}
|
|
283
|
+
function escapeHtml(s) {
|
|
284
|
+
return s
|
|
285
|
+
.replace(/&/g, "&")
|
|
286
|
+
.replace(/</g, "<")
|
|
287
|
+
.replace(/>/g, ">")
|
|
288
|
+
.replace(/"/g, """)
|
|
289
|
+
.replace(/'/g, "'");
|
|
290
|
+
}
|
|
291
|
+
// ---------------------------------------------------------------------------
|
|
292
|
+
// Session bridge — createResponseFromIdentity / endResponse.
|
|
293
|
+
//
|
|
294
|
+
// These delegate to the platform routes; the SDK never holds raw secrets.
|
|
295
|
+
// The session-minting route lives at POST /auth/v1/sessions/from-identity
|
|
296
|
+
// (gateway-internal). The endResponse helper just emits the clear-cookie
|
|
297
|
+
// Set-Cookie + body and lets the gateway-side mounted CSRF/origin check
|
|
298
|
+
// run on the calling capability's response.
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
async function createResponseFromIdentity(opts) {
|
|
301
|
+
const ctx = requireActiveContext("auth.sessions.createResponseFromIdentity");
|
|
302
|
+
const origin = `https://${ctx.host}`;
|
|
303
|
+
// Delegate to the platform route. The route verifies the proof
|
|
304
|
+
// against the project's registered verifier (wallet/oidc/custom) and
|
|
305
|
+
// mints the session via the internal-only primitive. The Response
|
|
306
|
+
// already carries Set-Cookie and the canonical {ok, user} body.
|
|
307
|
+
const res = await fetch(`${origin}/auth/v1/sessions/from-identity`, {
|
|
308
|
+
method: "POST",
|
|
309
|
+
headers: { "content-type": "application/json" },
|
|
310
|
+
body: JSON.stringify(opts),
|
|
311
|
+
redirect: "manual",
|
|
312
|
+
});
|
|
313
|
+
return res;
|
|
314
|
+
}
|
|
315
|
+
/** Header on the function's RETURNED Response that the gateway's routed-invoke
|
|
316
|
+
* post-processor materializes into a host-bound `Set-Cookie` — AFTER it
|
|
317
|
+
* checks the INVOKED function's declared `auth.sessionMint` capability
|
|
318
|
+
* (server-side; service-key presence is NOT sufficient). The gateway always
|
|
319
|
+
* strips this header before the client sees it. Kept in sync with the
|
|
320
|
+
* gateway constant of the same name. */
|
|
321
|
+
export const MINT_DIRECTIVE_HEADER = "x-run402-mint-directive";
|
|
322
|
+
/**
|
|
323
|
+
* Tenant-assertion session mint (D6) — for the tenant-owned-credential case
|
|
324
|
+
* where the calling function already verified the credential against its OWN
|
|
325
|
+
* store (bcrypt, custom DB, external IdP). This is NOT a proof-based mint;
|
|
326
|
+
* the tenant is *vouching*, so it is capability-gated (`auth.sessionMint` in
|
|
327
|
+
* the function's deploy spec), audited, and host-gated — all enforced by the
|
|
328
|
+
* gateway when it materializes the directive below.
|
|
329
|
+
*
|
|
330
|
+
* The shape is agent-proof: the platform derives `issuer: "tenant:<tenant>"`
|
|
331
|
+
* and `amr` from `method` (`password` → `tenant_password`, `sso` →
|
|
332
|
+
* `tenant_sso`). Arbitrary amr is available only via `advanced.amr`.
|
|
333
|
+
*
|
|
334
|
+
* Mechanism (pattern B): the SDK never holds the session secret, so it returns
|
|
335
|
+
* a Response carrying a `x-run402-mint-directive` header. The gateway reads it,
|
|
336
|
+
* verifies the invoked function declared `auth.sessionMint` (else
|
|
337
|
+
* `R402_AUTH_UNTRUSTED_CONTEXT`), validates the subject, mints the host-bound
|
|
338
|
+
* cookie, writes an audit row, strips the directive, and rewrites the body to
|
|
339
|
+
* `{ ok, user }`. Return it directly from your handler: `return
|
|
340
|
+
* auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })`.
|
|
341
|
+
*/
|
|
342
|
+
async function createResponseFromTenantAssertion(opts) {
|
|
343
|
+
// Must run inside a real routed invocation (not module scope / prerender).
|
|
344
|
+
requireActiveContext("auth.sessions.createResponseFromTenantAssertion");
|
|
345
|
+
// Fast SDK-side validation with the teaching fix. The gateway re-validates
|
|
346
|
+
// and additionally enforces `(project_id, issuer, user.id)` uniqueness.
|
|
347
|
+
const tenant = typeof opts?.tenant === "string" ? opts.tenant.trim() : "";
|
|
348
|
+
if (!tenant) {
|
|
349
|
+
throw new TenantSubjectInvalidError({ reason: "missing `tenant`" });
|
|
350
|
+
}
|
|
351
|
+
const user = opts?.user;
|
|
352
|
+
if (!user || typeof user !== "object") {
|
|
353
|
+
throw new TenantSubjectInvalidError({ reason: "missing `user`" });
|
|
354
|
+
}
|
|
355
|
+
const id = typeof user.id === "string" ? user.id.trim() : "";
|
|
356
|
+
if (!id) {
|
|
357
|
+
throw new TenantSubjectInvalidError({
|
|
358
|
+
reason: "`user.id` is required (a stable primary key, not a bare email)",
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
const email = typeof user.email === "string" ? user.email.trim() : "";
|
|
362
|
+
// The classic mistake: passing the email AS the id. A stable id is required.
|
|
363
|
+
if (id.includes("@") && id === email) {
|
|
364
|
+
throw new TenantSubjectInvalidError({
|
|
365
|
+
reason: "`user.id` must be a stable primary key, not the email",
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
if (opts.method !== "password" && opts.method !== "sso") {
|
|
369
|
+
throw new TenantSubjectInvalidError({
|
|
370
|
+
reason: '`method` must be "password" or "sso"',
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
const directive = {
|
|
374
|
+
v: 1,
|
|
375
|
+
tenant,
|
|
376
|
+
user: {
|
|
377
|
+
id,
|
|
378
|
+
email,
|
|
379
|
+
emailVerified: user.emailVerified === true,
|
|
380
|
+
...(user.displayName ? { displayName: String(user.displayName) } : {}),
|
|
381
|
+
...(user.avatarUrl ? { avatarUrl: String(user.avatarUrl) } : {}),
|
|
382
|
+
},
|
|
383
|
+
method: opts.method,
|
|
384
|
+
...(opts.advanced?.amr ? { advanced: { amr: opts.advanced.amr } } : {}),
|
|
385
|
+
};
|
|
386
|
+
const encoded = Buffer.from(JSON.stringify(directive), "utf8").toString("base64url");
|
|
387
|
+
// The response now depends on per-request actor state — taint the SSR cache.
|
|
388
|
+
taintCacheBypass();
|
|
389
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
390
|
+
status: 200,
|
|
391
|
+
headers: {
|
|
392
|
+
"content-type": "application/json",
|
|
393
|
+
[MINT_DIRECTIVE_HEADER]: encoded,
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/** Returns the canonical invalid-credentials error for the tenant-owned
|
|
398
|
+
* credential case. A FUNCTION, not a constructor (D9): write
|
|
399
|
+
* `throw auth.invalidCredentials()` — never `new auth.InvalidCredentialsError()`.
|
|
400
|
+
* Renders the canonical `R402_AUTH_INVALID_CREDENTIALS` envelope (distinct
|
|
401
|
+
* from `R402_AUTH_MAGIC_LINK_INVALID`); no session is minted. */
|
|
402
|
+
function invalidCredentials() {
|
|
403
|
+
return new InvalidCredentialsError();
|
|
404
|
+
}
|
|
405
|
+
async function endResponse() {
|
|
406
|
+
const ctx = requireActiveContext("auth.sessions.endResponse");
|
|
407
|
+
const origin = `https://${ctx.host}`;
|
|
408
|
+
const res = await fetch(`${origin}/auth/v1/sessions/end`, {
|
|
409
|
+
method: "POST",
|
|
410
|
+
headers: { "content-type": "application/json" },
|
|
411
|
+
redirect: "manual",
|
|
412
|
+
});
|
|
413
|
+
return res;
|
|
414
|
+
}
|
|
415
|
+
// ---------------------------------------------------------------------------
|
|
416
|
+
// Identity linking.
|
|
417
|
+
// ---------------------------------------------------------------------------
|
|
418
|
+
async function linkIdentity(opts) {
|
|
419
|
+
const ctx = requireActiveContext("auth.identities.link");
|
|
420
|
+
await requireUser();
|
|
421
|
+
const origin = `https://${ctx.host}`;
|
|
422
|
+
const res = await fetch(`${origin}/auth/v1/identities/link`, {
|
|
423
|
+
method: "POST",
|
|
424
|
+
headers: { "content-type": "application/json" },
|
|
425
|
+
body: JSON.stringify(opts),
|
|
426
|
+
redirect: "manual",
|
|
427
|
+
});
|
|
428
|
+
if (res.status === 409) {
|
|
429
|
+
// The platform route maps unique_violation on
|
|
430
|
+
// internal.identities (project_id, provider, subject) to 409.
|
|
431
|
+
throw new (await import("./errors.js")).IdentityLinkConflictError({
|
|
432
|
+
provider: opts.provider,
|
|
433
|
+
subject: opts.subject,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
if (!res.ok) {
|
|
437
|
+
const body = await res.json().catch(() => ({}));
|
|
438
|
+
throw new (await import("./errors.js")).SessionBridgeUnverifiedError({
|
|
439
|
+
reason: body.code ?? `link failed: ${res.status}`,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// ---------------------------------------------------------------------------
|
|
444
|
+
// SDK proxy intercepting hallucinated names.
|
|
445
|
+
// ---------------------------------------------------------------------------
|
|
446
|
+
const HALLUCINATED_NAMES = {
|
|
447
|
+
session: "auth.user() then read .sessionId / .amr / etc.",
|
|
448
|
+
getSession: "auth.user()",
|
|
449
|
+
currentUser: "auth.user()",
|
|
450
|
+
currentSession: "auth.user()",
|
|
451
|
+
requireAuth: "auth.requireUser()",
|
|
452
|
+
middleware: "auth.csrfField() / @run402/astro middleware",
|
|
453
|
+
signIn: "POST /auth/sign-in (browser form) or auth.sessions.createResponseFromIdentity({...})",
|
|
454
|
+
signout: "auth.sessions.endResponse()",
|
|
455
|
+
signOut: "auth.sessions.endResponse()",
|
|
456
|
+
logout: "auth.sessions.endResponse()",
|
|
457
|
+
login: "auth.sessions.createResponseFromIdentity({...})",
|
|
458
|
+
redirectToSignIn: "auth.requireUser() — platform redirects",
|
|
459
|
+
getUser: "auth.user()",
|
|
460
|
+
getToken: "auth.requireUser() then user.sessionId (tokens are not exposed)",
|
|
461
|
+
protect: "auth.requireUser() / auth.requireRole(...)",
|
|
462
|
+
// Section 5 — forbidden legacy mint names + common top-level typos.
|
|
463
|
+
signInResponse: "throw auth.invalidCredentials() on failure, then auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })",
|
|
464
|
+
InvalidCredentialsError: "auth.invalidCredentials()",
|
|
465
|
+
createResponseFromTenantSubject: "auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })",
|
|
466
|
+
createResponseFromTenantAssertion: "auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })",
|
|
467
|
+
createResponseFromIdentity: "auth.sessions.createResponseFromIdentity({ provider, subject, proof, amr })",
|
|
468
|
+
};
|
|
469
|
+
/** `auth.sessions.*` proxy — mirrors the top-level `auth` proxy so forbidden
|
|
470
|
+
* legacy names (`createResponseFromTenantSubject`, `signInResponse`) and
|
|
471
|
+
* typos throw the structured unknown-export error pointing at the canonical
|
|
472
|
+
* primitive, instead of silently returning `undefined`. */
|
|
473
|
+
const SESSIONS_HALLUCINATED_NAMES = {
|
|
474
|
+
createResponseFromTenantSubject: "auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })",
|
|
475
|
+
signInResponse: "auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })",
|
|
476
|
+
fromIdentity: "auth.sessions.createResponseFromIdentity({ ... })",
|
|
477
|
+
fromTenantAssertion: "auth.sessions.createResponseFromTenantAssertion({ tenant, user, method })",
|
|
478
|
+
};
|
|
479
|
+
const baseSessions = {
|
|
480
|
+
createResponseFromIdentity,
|
|
481
|
+
createResponseFromTenantAssertion,
|
|
482
|
+
endResponse,
|
|
483
|
+
};
|
|
484
|
+
const sessions = new Proxy(baseSessions, {
|
|
485
|
+
get(target, prop, receiver) {
|
|
486
|
+
if (typeof prop === "string" && !(prop in target)) {
|
|
487
|
+
throw new UnknownExportError({
|
|
488
|
+
attemptedName: `auth.sessions.${prop}`,
|
|
489
|
+
canonicalName: SESSIONS_HALLUCINATED_NAMES[prop] ??
|
|
490
|
+
"auth.sessions.createResponseFromIdentity / createResponseFromTenantAssertion / endResponse",
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return Reflect.get(target, prop, receiver);
|
|
494
|
+
},
|
|
495
|
+
});
|
|
496
|
+
const baseAuth = {
|
|
497
|
+
user,
|
|
498
|
+
requireUser,
|
|
499
|
+
requireRole,
|
|
500
|
+
requireMembership,
|
|
501
|
+
requireFresh,
|
|
502
|
+
fetch: authFetch,
|
|
503
|
+
csrfToken,
|
|
504
|
+
csrfField,
|
|
505
|
+
invalidCredentials,
|
|
506
|
+
identities: {
|
|
507
|
+
link: linkIdentity,
|
|
508
|
+
},
|
|
509
|
+
sessions,
|
|
510
|
+
};
|
|
511
|
+
/** Hallucinated-name proxy. Property access for a name not in
|
|
512
|
+
* `baseAuth` throws `R402_AUTH_UNKNOWN_EXPORT` with the canonical
|
|
513
|
+
* replacement. Hot-path access (existing keys) returns the actual
|
|
514
|
+
* helper — proxy overhead is one Reflect.has + Reflect.get. */
|
|
515
|
+
export const auth = new Proxy(baseAuth, {
|
|
516
|
+
get(target, prop, receiver) {
|
|
517
|
+
if (typeof prop === "string" && !(prop in target)) {
|
|
518
|
+
const replacement = HALLUCINATED_NAMES[prop];
|
|
519
|
+
if (replacement) {
|
|
520
|
+
throw new UnknownExportError({
|
|
521
|
+
attemptedName: `auth.${prop}`,
|
|
522
|
+
canonicalName: replacement,
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
throw new UnknownExportError({
|
|
526
|
+
attemptedName: `auth.${prop}`,
|
|
527
|
+
canonicalName: "auth.user / auth.requireUser / auth.requireRole / auth.requireMembership",
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return Reflect.get(target, prop, receiver);
|
|
531
|
+
},
|
|
532
|
+
});
|
|
533
|
+
/** Throwing-sentinel exports for the top hallucinated *bare* names.
|
|
534
|
+
* ESM `import { getUser } from "@run402/functions"` can be intercepted
|
|
535
|
+
* only by a real export — so we ship these as exported throwing
|
|
536
|
+
* functions. They're marked `@deprecated` in the type JSDoc; the SDK
|
|
537
|
+
* proxy + lint registry + `run402 doctor` scan all flag the import
|
|
538
|
+
* before runtime if the user is running the tooling.
|
|
539
|
+
*
|
|
540
|
+
* Excluded from public docs and AGENTS.md per the spec.
|
|
541
|
+
*/
|
|
542
|
+
/** @deprecated Use `auth.user()` or `auth.requireUser()`. */
|
|
543
|
+
export function getSession() {
|
|
544
|
+
throw new UnknownExportError({ attemptedName: "getSession", canonicalName: "auth.user()" });
|
|
545
|
+
}
|
|
546
|
+
/** @deprecated Use `auth.user()`. */
|
|
547
|
+
export function currentUser() {
|
|
548
|
+
throw new UnknownExportError({ attemptedName: "currentUser", canonicalName: "auth.user()" });
|
|
549
|
+
}
|
|
550
|
+
/** @deprecated Use `auth.user()`. */
|
|
551
|
+
export function getCurrentUser() {
|
|
552
|
+
throw new UnknownExportError({ attemptedName: "getCurrentUser", canonicalName: "auth.user()" });
|
|
553
|
+
}
|
|
554
|
+
/** @deprecated Use `auth.user()`. */
|
|
555
|
+
export function getServerSession() {
|
|
556
|
+
throw new UnknownExportError({
|
|
557
|
+
attemptedName: "getServerSession",
|
|
558
|
+
canonicalName: "auth.user()",
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
// ---------------------------------------------------------------------------
|
|
562
|
+
// Internal helpers
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
function actorContextToPublicActor(ctxActor, projectId) {
|
|
565
|
+
if (!ctxActor)
|
|
566
|
+
return null;
|
|
567
|
+
return {
|
|
568
|
+
id: ctxActor.id,
|
|
569
|
+
projectId,
|
|
570
|
+
sessionId: ctxActor.sessionId,
|
|
571
|
+
email: ctxActor.email,
|
|
572
|
+
emailVerified: ctxActor.emailVerified,
|
|
573
|
+
authTime: ctxActor.authTime,
|
|
574
|
+
amr: [...ctxActor.amr],
|
|
575
|
+
amrTimes: { ...ctxActor.amrTimes },
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function currentReturnTo() {
|
|
579
|
+
const ctx = getCurrentContext();
|
|
580
|
+
if (!ctx)
|
|
581
|
+
return undefined;
|
|
582
|
+
return ctx.request.url;
|
|
583
|
+
}
|
|
584
|
+
export { AuthRequiredError, InsufficientRoleError, InsufficientMembershipError, FreshnessRequiredError, FetchAbsoluteUrlError, PrerenderedError, UnknownExportError, SessionBridgeUnverifiedError, IdentityLinkConflictError, UnknownIdentityError, InvalidCredentialsError, TenantSubjectInvalidError, Run402AuthError, } from "./errors.js";
|
|
585
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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"}
|