@spfn/auth 0.3.0-beta.2 → 0.3.0-beta.20

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.
Files changed (43) hide show
  1. package/README.md +1382 -23
  2. package/dist/client-proof.d.ts +45 -15
  3. package/dist/client-proof.js +198 -4
  4. package/dist/client-proof.js.map +1 -1
  5. package/dist/client.d.ts +92 -1
  6. package/dist/client.js +58 -0
  7. package/dist/client.js.map +1 -1
  8. package/dist/config.d.ts +302 -0
  9. package/dist/config.js +134 -4
  10. package/dist/config.js.map +1 -1
  11. package/dist/errors.d.ts +370 -3
  12. package/dist/errors.js +245 -2
  13. package/dist/errors.js.map +1 -1
  14. package/dist/index.d.ts +185 -2
  15. package/dist/index.js +256 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/machine-principals-BD4tnASp.d.ts +2739 -0
  18. package/dist/nextjs/api.js +350 -12
  19. package/dist/nextjs/api.js.map +1 -1
  20. package/dist/nextjs/client.d.ts +28 -1
  21. package/dist/nextjs/client.js +24 -3
  22. package/dist/nextjs/client.js.map +1 -1
  23. package/dist/nextjs/server.d.ts +173 -3
  24. package/dist/nextjs/server.js +372 -10
  25. package/dist/nextjs/server.js.map +1 -1
  26. package/dist/server.d.ts +3761 -414
  27. package/dist/server.js +5865 -1043
  28. package/dist/server.js.map +1 -1
  29. package/dist/{session-DTHahDQ9.d.ts → session-Dfwu5g2W.d.ts} +28 -1
  30. package/migrations/20260810112144_colorful_tomorrow_man/migration.sql +18 -0
  31. package/migrations/20260810112144_colorful_tomorrow_man/snapshot.json +3576 -0
  32. package/migrations/20260901091716_fine_arclight/migration.sql +21 -0
  33. package/migrations/20260901091716_fine_arclight/snapshot.json +3849 -0
  34. package/migrations/20260906155957_natural_moonstone/migration.sql +33 -0
  35. package/migrations/20260906155957_natural_moonstone/snapshot.json +4275 -0
  36. package/migrations/20260907020904_giant_eternals/migration.sql +21 -0
  37. package/migrations/20260907020904_giant_eternals/snapshot.json +4561 -0
  38. package/migrations/20260907044807_eminent_angel/migration.sql +2 -0
  39. package/migrations/20260907044807_eminent_angel/snapshot.json +4561 -0
  40. package/migrations/20260918083158_foamy_roughhouse/migration.sql +55 -0
  41. package/migrations/20260918083158_foamy_roughhouse/snapshot.json +5271 -0
  42. package/package.json +9 -6
  43. package/dist/authenticate-55LeXHqZ.d.ts +0 -1447
package/dist/client.d.ts CHANGED
@@ -1,2 +1,93 @@
1
+ import { authApi } from '@spfn/auth';
1
2
 
2
- export { }
3
+ /**
4
+ * @spfn/auth/client - Passkeys (WebAuthn)
5
+ *
6
+ * Four browser helpers over the two ceremonies. Each one is `options` from the
7
+ * server, `navigator.credentials` in the browser, `verify` back to the server —
8
+ * and each answers with a discriminated union instead of throwing.
9
+ *
10
+ * That is the whole point of this file. A person closing the system passkey
11
+ * sheet raises `NotAllowedError`, and so does a person whose authenticator has
12
+ * nothing to offer; neither is an application error, and code that has to tell
13
+ * them apart by catching and re-reading `error.name` gets it wrong once and
14
+ * shows a red banner to someone who simply changed their mind.
15
+ *
16
+ * Ships to browsers: no Node built-ins here, `Buffer` included. The base64url
17
+ * helpers come from `@simplewebauthn/browser`, which is bundled into this entry.
18
+ */
19
+
20
+ /** The typed auth client these helpers drive. */
21
+ type AuthApi = typeof authApi;
22
+ /**
23
+ * Why a ceremony did not produce a session.
24
+ *
25
+ * - `unsupported`: this browser has no WebAuthn at all
26
+ * - `cancelled`: the person dismissed the prompt
27
+ * - `no-credential`: the authenticator had nothing for this relying party
28
+ * - `error`: anything else, with the original error attached
29
+ */
30
+ type PasskeyFailureReason = 'unsupported' | 'cancelled' | 'no-credential' | 'error';
31
+ type PasskeyResult<T> = ({
32
+ ok: true;
33
+ } & T) | {
34
+ ok: false;
35
+ reason: PasskeyFailureReason;
36
+ error?: unknown;
37
+ };
38
+ /** Whether this browser can run a WebAuthn ceremony at all. */
39
+ declare function isPasskeySupported(): boolean;
40
+ /**
41
+ * Whether the browser can offer passkeys inside the ordinary autofill dropdown.
42
+ *
43
+ * Worth checking before rendering a sign-in form: conditional mediation is what
44
+ * turns a passkey into "tap the suggestion above the keyboard", and where it is
45
+ * missing the form needs a visible "Sign in with a passkey" button instead.
46
+ */
47
+ declare function isConditionalMediationAvailable(): Promise<boolean>;
48
+ interface EnrollPasskeyOptions {
49
+ /** Owner-facing name for the passkey list, e.g. the device model. */
50
+ label?: string;
51
+ /** Sent when the session proved itself longer ago than the recent-auth window. */
52
+ currentPassword?: string;
53
+ }
54
+ interface EnrollPasskeyValue {
55
+ passkeyId: string;
56
+ label: string | null;
57
+ createdAt: string;
58
+ }
59
+ /**
60
+ * Enroll a passkey on the device in front of the user.
61
+ *
62
+ * Requires a signed-in session. A 403 with code `RECENT_AUTH_REQUIRED` from the
63
+ * options call means the caller should prompt for the password and try again
64
+ * with `currentPassword`; that is a rejected promise, not a result here, because
65
+ * it is the server declining rather than the ceremony failing.
66
+ */
67
+ declare function enrollPasskey(api: AuthApi, options?: EnrollPasskeyOptions): Promise<PasskeyResult<EnrollPasskeyValue>>;
68
+ interface SignInWithPasskeyOptions {
69
+ /**
70
+ * Offer the passkey through the browser's autofill dropdown instead of a
71
+ * modal. Needs an `<input autocomplete="username webauthn">` on the page.
72
+ */
73
+ conditional?: boolean;
74
+ deviceName?: string;
75
+ platform?: string;
76
+ }
77
+ interface SignInWithPasskeyValue {
78
+ userId: string;
79
+ publicId: string;
80
+ email?: string;
81
+ phone?: string;
82
+ passwordChangeRequired: boolean;
83
+ }
84
+ /**
85
+ * Sign in with a passkey, no identifier asked for.
86
+ *
87
+ * The device key the session runs on is generated and stored by the Next.js
88
+ * proxy interceptor, exactly as on a password login — nothing here handles a
89
+ * private key.
90
+ */
91
+ declare function signInWithPasskey(api: AuthApi, options?: SignInWithPasskeyOptions): Promise<PasskeyResult<SignInWithPasskeyValue>>;
92
+
93
+ export { type AuthApi, type EnrollPasskeyOptions, type EnrollPasskeyValue, type PasskeyFailureReason, type PasskeyResult, type SignInWithPasskeyOptions, type SignInWithPasskeyValue, enrollPasskey, isConditionalMediationAvailable, isPasskeySupported, signInWithPasskey };
package/dist/client.js CHANGED
@@ -1 +1,59 @@
1
+ // src/client/passkeys.ts
2
+ import {
3
+ browserSupportsWebAuthn,
4
+ browserSupportsWebAuthnAutofill,
5
+ startAuthentication,
6
+ startRegistration
7
+ } from "@simplewebauthn/browser";
8
+ function isPasskeySupported() {
9
+ return browserSupportsWebAuthn();
10
+ }
11
+ async function isConditionalMediationAvailable() {
12
+ return await browserSupportsWebAuthnAutofill();
13
+ }
14
+ function failureReason(error, whenNotAllowed) {
15
+ return error?.name === "NotAllowedError" ? whenNotAllowed : "error";
16
+ }
17
+ async function enrollPasskey(api, options = {}) {
18
+ if (!isPasskeySupported()) {
19
+ return { ok: false, reason: "unsupported" };
20
+ }
21
+ const optionsJSON = await api.passkeyRegisterOptions.call({
22
+ body: { currentPassword: options.currentPassword }
23
+ });
24
+ let response;
25
+ try {
26
+ response = await startRegistration({ optionsJSON });
27
+ } catch (error) {
28
+ return { ok: false, reason: failureReason(error, "cancelled"), error };
29
+ }
30
+ const enrolled = await api.passkeyRegisterVerify.call({
31
+ body: { response, label: options.label }
32
+ });
33
+ return { ok: true, ...enrolled };
34
+ }
35
+ async function signInWithPasskey(api, options = {}) {
36
+ if (!isPasskeySupported()) {
37
+ return { ok: false, reason: "unsupported" };
38
+ }
39
+ const optionsJSON = await api.passkeyLoginOptions.call({
40
+ body: {}
41
+ });
42
+ let response;
43
+ try {
44
+ response = await startAuthentication({ optionsJSON, useBrowserAutofill: options.conditional === true });
45
+ } catch (error) {
46
+ return { ok: false, reason: failureReason(error, "no-credential"), error };
47
+ }
48
+ const session = await api.passkeyLoginVerify.call({
49
+ body: { response }
50
+ });
51
+ return { ok: true, ...session };
52
+ }
53
+ export {
54
+ enrollPasskey,
55
+ isConditionalMediationAvailable,
56
+ isPasskeySupported,
57
+ signInWithPasskey
58
+ };
1
59
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/client/passkeys.ts"],"sourcesContent":["/**\n * @spfn/auth/client - Passkeys (WebAuthn)\n *\n * Four browser helpers over the two ceremonies. Each one is `options` from the\n * server, `navigator.credentials` in the browser, `verify` back to the server —\n * and each answers with a discriminated union instead of throwing.\n *\n * That is the whole point of this file. A person closing the system passkey\n * sheet raises `NotAllowedError`, and so does a person whose authenticator has\n * nothing to offer; neither is an application error, and code that has to tell\n * them apart by catching and re-reading `error.name` gets it wrong once and\n * shows a red banner to someone who simply changed their mind.\n *\n * Ships to browsers: no Node built-ins here, `Buffer` included. The base64url\n * helpers come from `@simplewebauthn/browser`, which is bundled into this entry.\n */\n\nimport {\n browserSupportsWebAuthn,\n browserSupportsWebAuthnAutofill,\n startAuthentication,\n startRegistration,\n type AuthenticationResponseJSON,\n type PublicKeyCredentialCreationOptionsJSON,\n type PublicKeyCredentialRequestOptionsJSON,\n type RegistrationResponseJSON,\n} from '@simplewebauthn/browser';\n\nimport type { authApi } from '@spfn/auth';\n\n/** The typed auth client these helpers drive. */\nexport type AuthApi = typeof authApi;\n\n/**\n * Why a ceremony did not produce a session.\n *\n * - `unsupported`: this browser has no WebAuthn at all\n * - `cancelled`: the person dismissed the prompt\n * - `no-credential`: the authenticator had nothing for this relying party\n * - `error`: anything else, with the original error attached\n */\nexport type PasskeyFailureReason = 'unsupported' | 'cancelled' | 'no-credential' | 'error';\n\nexport type PasskeyResult<T> =\n | ({ ok: true } & T)\n | { ok: false; reason: PasskeyFailureReason; error?: unknown };\n\n/** Whether this browser can run a WebAuthn ceremony at all. */\nexport function isPasskeySupported(): boolean\n{\n return browserSupportsWebAuthn();\n}\n\n/**\n * Whether the browser can offer passkeys inside the ordinary autofill dropdown.\n *\n * Worth checking before rendering a sign-in form: conditional mediation is what\n * turns a passkey into \"tap the suggestion above the keyboard\", and where it is\n * missing the form needs a visible \"Sign in with a passkey\" button instead.\n */\nexport async function isConditionalMediationAvailable(): Promise<boolean>\n{\n return await browserSupportsWebAuthnAutofill();\n}\n\n/**\n * The reason a ceremony failure should be reported as.\n *\n * `NotAllowedError` is the browser's answer both to \"the person said no\" and to\n * \"nothing here matched\", and the specification deliberately does not\n * distinguish them — telling a caller which applied would say whether a\n * credential for this site exists on the device. So it is `cancelled` in both\n * cases on registration, and `no-credential` on a sign-in that offered no\n * credentials to choose from, which is the reading a UI wants.\n */\nfunction failureReason(error: unknown, whenNotAllowed: PasskeyFailureReason): PasskeyFailureReason\n{\n return (error as { name?: string } | null)?.name === 'NotAllowedError' ? whenNotAllowed : 'error';\n}\n\nexport interface EnrollPasskeyOptions\n{\n /** Owner-facing name for the passkey list, e.g. the device model. */\n label?: string;\n /** Sent when the session proved itself longer ago than the recent-auth window. */\n currentPassword?: string;\n}\n\nexport interface EnrollPasskeyValue\n{\n passkeyId: string;\n label: string | null;\n createdAt: string;\n}\n\n/**\n * Enroll a passkey on the device in front of the user.\n *\n * Requires a signed-in session. A 403 with code `RECENT_AUTH_REQUIRED` from the\n * options call means the caller should prompt for the password and try again\n * with `currentPassword`; that is a rejected promise, not a result here, because\n * it is the server declining rather than the ceremony failing.\n */\nexport async function enrollPasskey(\n api: AuthApi,\n options: EnrollPasskeyOptions = {},\n): Promise<PasskeyResult<EnrollPasskeyValue>>\n{\n if (!isPasskeySupported())\n {\n return { ok: false, reason: 'unsupported' };\n }\n\n const optionsJSON = await api.passkeyRegisterOptions.call({\n body: { currentPassword: options.currentPassword },\n }) as PublicKeyCredentialCreationOptionsJSON;\n\n let response: RegistrationResponseJSON;\n\n try\n {\n response = await startRegistration({ optionsJSON });\n }\n catch (error)\n {\n return { ok: false, reason: failureReason(error, 'cancelled'), error };\n }\n\n const enrolled = await api.passkeyRegisterVerify.call({\n body: { response, label: options.label },\n }) as EnrollPasskeyValue;\n\n return { ok: true, ...enrolled };\n}\n\nexport interface SignInWithPasskeyOptions\n{\n /**\n * Offer the passkey through the browser's autofill dropdown instead of a\n * modal. Needs an `<input autocomplete=\"username webauthn\">` on the page.\n */\n conditional?: boolean;\n deviceName?: string;\n platform?: string;\n}\n\nexport interface SignInWithPasskeyValue\n{\n userId: string;\n publicId: string;\n email?: string;\n phone?: string;\n passwordChangeRequired: boolean;\n}\n\n/**\n * Sign in with a passkey, no identifier asked for.\n *\n * The device key the session runs on is generated and stored by the Next.js\n * proxy interceptor, exactly as on a password login — nothing here handles a\n * private key.\n */\nexport async function signInWithPasskey(\n api: AuthApi,\n options: SignInWithPasskeyOptions = {},\n): Promise<PasskeyResult<SignInWithPasskeyValue>>\n{\n if (!isPasskeySupported())\n {\n return { ok: false, reason: 'unsupported' };\n }\n\n const optionsJSON = await api.passkeyLoginOptions.call({\n body: {},\n }) as PublicKeyCredentialRequestOptionsJSON;\n\n let response: AuthenticationResponseJSON;\n\n try\n {\n response = await startAuthentication({ optionsJSON, useBrowserAutofill: options.conditional === true });\n }\n catch (error)\n {\n return { ok: false, reason: failureReason(error, 'no-credential'), error };\n }\n\n const session = await api.passkeyLoginVerify.call({\n body: { response },\n }) as SignInWithPasskeyValue;\n\n return { ok: true, ...session };\n}\n"],"mappings":";AAiBA;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKG;AAsBA,SAAS,qBAChB;AACI,SAAO,wBAAwB;AACnC;AASA,eAAsB,kCACtB;AACI,SAAO,MAAM,gCAAgC;AACjD;AAYA,SAAS,cAAc,OAAgB,gBACvC;AACI,SAAQ,OAAoC,SAAS,oBAAoB,iBAAiB;AAC9F;AAyBA,eAAsB,cAClB,KACA,UAAgC,CAAC,GAErC;AACI,MAAI,CAAC,mBAAmB,GACxB;AACI,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAC9C;AAEA,QAAM,cAAc,MAAM,IAAI,uBAAuB,KAAK;AAAA,IACtD,MAAM,EAAE,iBAAiB,QAAQ,gBAAgB;AAAA,EACrD,CAAC;AAED,MAAI;AAEJ,MACA;AACI,eAAW,MAAM,kBAAkB,EAAE,YAAY,CAAC;AAAA,EACtD,SACO,OACP;AACI,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc,OAAO,WAAW,GAAG,MAAM;AAAA,EACzE;AAEA,QAAM,WAAW,MAAM,IAAI,sBAAsB,KAAK;AAAA,IAClD,MAAM,EAAE,UAAU,OAAO,QAAQ,MAAM;AAAA,EAC3C,CAAC;AAED,SAAO,EAAE,IAAI,MAAM,GAAG,SAAS;AACnC;AA6BA,eAAsB,kBAClB,KACA,UAAoC,CAAC,GAEzC;AACI,MAAI,CAAC,mBAAmB,GACxB;AACI,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc;AAAA,EAC9C;AAEA,QAAM,cAAc,MAAM,IAAI,oBAAoB,KAAK;AAAA,IACnD,MAAM,CAAC;AAAA,EACX,CAAC;AAED,MAAI;AAEJ,MACA;AACI,eAAW,MAAM,oBAAoB,EAAE,aAAa,oBAAoB,QAAQ,gBAAgB,KAAK,CAAC;AAAA,EAC1G,SACO,OACP;AACI,WAAO,EAAE,IAAI,OAAO,QAAQ,cAAc,OAAO,eAAe,GAAG,MAAM;AAAA,EAC7E;AAEA,QAAM,UAAU,MAAM,IAAI,mBAAmB,KAAK;AAAA,IAC9C,MAAM,EAAE,SAAS;AAAA,EACrB,CAAC;AAED,SAAO,EAAE,IAAI,MAAM,GAAG,QAAQ;AAClC;","names":[]}
package/dist/config.d.ts CHANGED
@@ -80,6 +80,16 @@ declare const authEnvSchema: {
80
80
  } & {
81
81
  key: "SPFN_AUTH_COOKIE_SECURE";
82
82
  };
83
+ SPFN_AUTH_CSRF: {
84
+ description: string;
85
+ required: boolean;
86
+ nextjs: boolean;
87
+ examples: string[];
88
+ type: "string";
89
+ validator: (value: string) => string;
90
+ } & {
91
+ key: "SPFN_AUTH_CSRF";
92
+ };
83
93
  SPFN_AUTH_BCRYPT_SALT_ROUNDS: {
84
94
  key: string;
85
95
  description: string;
@@ -195,6 +205,138 @@ declare const authEnvSchema: {
195
205
  } & {
196
206
  key: "SPFN_AUTH_USERNAME_MAX_LENGTH";
197
207
  };
208
+ SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES: {
209
+ description: string;
210
+ default: number;
211
+ required: boolean;
212
+ examples: number[];
213
+ type: "number";
214
+ validator: (value: string) => number;
215
+ } & {
216
+ key: "SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES";
217
+ };
218
+ SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES: {
219
+ description: string;
220
+ default: number;
221
+ required: boolean;
222
+ examples: number[];
223
+ type: "number";
224
+ validator: (value: string) => number;
225
+ } & {
226
+ key: "SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES";
227
+ };
228
+ SPFN_AUTH_SIGNUP_CONFIRM_PATH: {
229
+ description: string;
230
+ default: string;
231
+ required: boolean;
232
+ examples: string[];
233
+ type: "string";
234
+ validator: (value: string) => string;
235
+ } & {
236
+ key: "SPFN_AUTH_SIGNUP_CONFIRM_PATH";
237
+ };
238
+ SPFN_AUTH_PASSWORD_RESET_LINK_TTL_MINUTES: {
239
+ description: string;
240
+ default: number;
241
+ required: boolean;
242
+ examples: number[];
243
+ type: "number";
244
+ validator: (value: string) => number;
245
+ } & {
246
+ key: "SPFN_AUTH_PASSWORD_RESET_LINK_TTL_MINUTES";
247
+ };
248
+ SPFN_AUTH_PASSWORD_RESET_SETUP_TTL_MINUTES: {
249
+ description: string;
250
+ default: number;
251
+ required: boolean;
252
+ examples: number[];
253
+ type: "number";
254
+ validator: (value: string) => number;
255
+ } & {
256
+ key: "SPFN_AUTH_PASSWORD_RESET_SETUP_TTL_MINUTES";
257
+ };
258
+ SPFN_AUTH_PASSWORD_RESET_CONFIRM_PATH: {
259
+ description: string;
260
+ default: string;
261
+ required: boolean;
262
+ examples: string[];
263
+ type: "string";
264
+ validator: (value: string) => string;
265
+ } & {
266
+ key: "SPFN_AUTH_PASSWORD_RESET_CONFIRM_PATH";
267
+ };
268
+ SPFN_AUTH_LINK_MAIL_DELIVERY: {
269
+ description: string;
270
+ default?: "auto" | "inline" | "queued" | undefined;
271
+ examples?: ("auto" | "inline" | "queued")[] | undefined;
272
+ minLength?: number | undefined;
273
+ required?: boolean | undefined;
274
+ fallbackKeys?: string[] | undefined;
275
+ sensitive?: boolean | undefined;
276
+ generate?: "hex32" | "hex64" | "uuid" | "base64url32" | undefined;
277
+ nextjs?: boolean | undefined;
278
+ type: "enum";
279
+ validator: (val: string) => "auto" | "inline" | "queued";
280
+ } & {
281
+ key: "SPFN_AUTH_LINK_MAIL_DELIVERY";
282
+ };
283
+ SPFN_AUTH_PASSKEY_RP_ID: {
284
+ description: string;
285
+ required: boolean;
286
+ examples: string[];
287
+ type: "string";
288
+ validator: (value: string) => string;
289
+ } & {
290
+ key: "SPFN_AUTH_PASSKEY_RP_ID";
291
+ };
292
+ SPFN_AUTH_PASSKEY_RP_NAME: {
293
+ description: string;
294
+ required: boolean;
295
+ examples: string[];
296
+ type: "string";
297
+ validator: (value: string) => string;
298
+ } & {
299
+ key: "SPFN_AUTH_PASSKEY_RP_NAME";
300
+ };
301
+ SPFN_AUTH_PASSKEY_ORIGINS: {
302
+ description: string;
303
+ required: boolean;
304
+ examples: string[];
305
+ type: "string";
306
+ validator: (value: string) => string;
307
+ } & {
308
+ key: "SPFN_AUTH_PASSKEY_ORIGINS";
309
+ };
310
+ SPFN_AUTH_PASSKEY_USER_VERIFICATION: {
311
+ description: string;
312
+ default: string;
313
+ required: boolean;
314
+ examples: string[];
315
+ type: "string";
316
+ validator: (value: string) => string;
317
+ } & {
318
+ key: "SPFN_AUTH_PASSKEY_USER_VERIFICATION";
319
+ };
320
+ SPFN_AUTH_PASSKEY_CHALLENGE_TTL_SECONDS: {
321
+ description: string;
322
+ default: number;
323
+ required: boolean;
324
+ examples: number[];
325
+ type: "number";
326
+ validator: (value: string) => number;
327
+ } & {
328
+ key: "SPFN_AUTH_PASSKEY_CHALLENGE_TTL_SECONDS";
329
+ };
330
+ SPFN_AUTH_PASSKEY_RECENT_AUTH_MINUTES: {
331
+ description: string;
332
+ default: number;
333
+ required: boolean;
334
+ examples: number[];
335
+ type: "number";
336
+ validator: (value: string) => number;
337
+ } & {
338
+ key: "SPFN_AUTH_PASSKEY_RECENT_AUTH_MINUTES";
339
+ };
198
340
  SPFN_API_URL: {
199
341
  description: string;
200
342
  default: string;
@@ -382,6 +524,15 @@ declare const authEnvSchema: {
382
524
  } & {
383
525
  key: "SPFN_AUTH_GITHUB_REDIRECT_URI";
384
526
  };
527
+ SPFN_AUTH_OAUTH_CALLBACK_ORIGIN_CHECK: {
528
+ description: string;
529
+ required: boolean;
530
+ examples: string[];
531
+ type: "string";
532
+ validator: (value: string) => string;
533
+ } & {
534
+ key: "SPFN_AUTH_OAUTH_CALLBACK_ORIGIN_CHECK";
535
+ };
385
536
  SPFN_AUTH_GOOGLE_NATIVE_CLIENT_IDS: {
386
537
  description: string;
387
538
  required: boolean;
@@ -494,6 +645,16 @@ declare const env: _spfn_core_env.InferEnvType<{
494
645
  } & {
495
646
  key: "SPFN_AUTH_COOKIE_SECURE";
496
647
  };
648
+ SPFN_AUTH_CSRF: {
649
+ description: string;
650
+ required: boolean;
651
+ nextjs: boolean;
652
+ examples: string[];
653
+ type: "string";
654
+ validator: (value: string) => string;
655
+ } & {
656
+ key: "SPFN_AUTH_CSRF";
657
+ };
497
658
  SPFN_AUTH_BCRYPT_SALT_ROUNDS: {
498
659
  key: string;
499
660
  description: string;
@@ -609,6 +770,138 @@ declare const env: _spfn_core_env.InferEnvType<{
609
770
  } & {
610
771
  key: "SPFN_AUTH_USERNAME_MAX_LENGTH";
611
772
  };
773
+ SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES: {
774
+ description: string;
775
+ default: number;
776
+ required: boolean;
777
+ examples: number[];
778
+ type: "number";
779
+ validator: (value: string) => number;
780
+ } & {
781
+ key: "SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES";
782
+ };
783
+ SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES: {
784
+ description: string;
785
+ default: number;
786
+ required: boolean;
787
+ examples: number[];
788
+ type: "number";
789
+ validator: (value: string) => number;
790
+ } & {
791
+ key: "SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES";
792
+ };
793
+ SPFN_AUTH_SIGNUP_CONFIRM_PATH: {
794
+ description: string;
795
+ default: string;
796
+ required: boolean;
797
+ examples: string[];
798
+ type: "string";
799
+ validator: (value: string) => string;
800
+ } & {
801
+ key: "SPFN_AUTH_SIGNUP_CONFIRM_PATH";
802
+ };
803
+ SPFN_AUTH_PASSWORD_RESET_LINK_TTL_MINUTES: {
804
+ description: string;
805
+ default: number;
806
+ required: boolean;
807
+ examples: number[];
808
+ type: "number";
809
+ validator: (value: string) => number;
810
+ } & {
811
+ key: "SPFN_AUTH_PASSWORD_RESET_LINK_TTL_MINUTES";
812
+ };
813
+ SPFN_AUTH_PASSWORD_RESET_SETUP_TTL_MINUTES: {
814
+ description: string;
815
+ default: number;
816
+ required: boolean;
817
+ examples: number[];
818
+ type: "number";
819
+ validator: (value: string) => number;
820
+ } & {
821
+ key: "SPFN_AUTH_PASSWORD_RESET_SETUP_TTL_MINUTES";
822
+ };
823
+ SPFN_AUTH_PASSWORD_RESET_CONFIRM_PATH: {
824
+ description: string;
825
+ default: string;
826
+ required: boolean;
827
+ examples: string[];
828
+ type: "string";
829
+ validator: (value: string) => string;
830
+ } & {
831
+ key: "SPFN_AUTH_PASSWORD_RESET_CONFIRM_PATH";
832
+ };
833
+ SPFN_AUTH_LINK_MAIL_DELIVERY: {
834
+ description: string;
835
+ default?: "auto" | "inline" | "queued" | undefined;
836
+ examples?: ("auto" | "inline" | "queued")[] | undefined;
837
+ minLength?: number | undefined;
838
+ required?: boolean | undefined;
839
+ fallbackKeys?: string[] | undefined;
840
+ sensitive?: boolean | undefined;
841
+ generate?: "hex32" | "hex64" | "uuid" | "base64url32" | undefined;
842
+ nextjs?: boolean | undefined;
843
+ type: "enum";
844
+ validator: (val: string) => "auto" | "inline" | "queued";
845
+ } & {
846
+ key: "SPFN_AUTH_LINK_MAIL_DELIVERY";
847
+ };
848
+ SPFN_AUTH_PASSKEY_RP_ID: {
849
+ description: string;
850
+ required: boolean;
851
+ examples: string[];
852
+ type: "string";
853
+ validator: (value: string) => string;
854
+ } & {
855
+ key: "SPFN_AUTH_PASSKEY_RP_ID";
856
+ };
857
+ SPFN_AUTH_PASSKEY_RP_NAME: {
858
+ description: string;
859
+ required: boolean;
860
+ examples: string[];
861
+ type: "string";
862
+ validator: (value: string) => string;
863
+ } & {
864
+ key: "SPFN_AUTH_PASSKEY_RP_NAME";
865
+ };
866
+ SPFN_AUTH_PASSKEY_ORIGINS: {
867
+ description: string;
868
+ required: boolean;
869
+ examples: string[];
870
+ type: "string";
871
+ validator: (value: string) => string;
872
+ } & {
873
+ key: "SPFN_AUTH_PASSKEY_ORIGINS";
874
+ };
875
+ SPFN_AUTH_PASSKEY_USER_VERIFICATION: {
876
+ description: string;
877
+ default: string;
878
+ required: boolean;
879
+ examples: string[];
880
+ type: "string";
881
+ validator: (value: string) => string;
882
+ } & {
883
+ key: "SPFN_AUTH_PASSKEY_USER_VERIFICATION";
884
+ };
885
+ SPFN_AUTH_PASSKEY_CHALLENGE_TTL_SECONDS: {
886
+ description: string;
887
+ default: number;
888
+ required: boolean;
889
+ examples: number[];
890
+ type: "number";
891
+ validator: (value: string) => number;
892
+ } & {
893
+ key: "SPFN_AUTH_PASSKEY_CHALLENGE_TTL_SECONDS";
894
+ };
895
+ SPFN_AUTH_PASSKEY_RECENT_AUTH_MINUTES: {
896
+ description: string;
897
+ default: number;
898
+ required: boolean;
899
+ examples: number[];
900
+ type: "number";
901
+ validator: (value: string) => number;
902
+ } & {
903
+ key: "SPFN_AUTH_PASSKEY_RECENT_AUTH_MINUTES";
904
+ };
612
905
  SPFN_API_URL: {
613
906
  description: string;
614
907
  default: string;
@@ -796,6 +1089,15 @@ declare const env: _spfn_core_env.InferEnvType<{
796
1089
  } & {
797
1090
  key: "SPFN_AUTH_GITHUB_REDIRECT_URI";
798
1091
  };
1092
+ SPFN_AUTH_OAUTH_CALLBACK_ORIGIN_CHECK: {
1093
+ description: string;
1094
+ required: boolean;
1095
+ examples: string[];
1096
+ type: "string";
1097
+ validator: (value: string) => string;
1098
+ } & {
1099
+ key: "SPFN_AUTH_OAUTH_CALLBACK_ORIGIN_CHECK";
1100
+ };
799
1101
  SPFN_AUTH_GOOGLE_NATIVE_CLIENT_IDS: {
800
1102
  description: string;
801
1103
  required: boolean;