@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.
- package/README.md +1382 -23
- package/dist/client-proof.d.ts +45 -15
- package/dist/client-proof.js +198 -4
- package/dist/client-proof.js.map +1 -1
- package/dist/client.d.ts +92 -1
- package/dist/client.js +58 -0
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +302 -0
- package/dist/config.js +134 -4
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +370 -3
- package/dist/errors.js +245 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +185 -2
- package/dist/index.js +256 -2
- package/dist/index.js.map +1 -1
- package/dist/machine-principals-BD4tnASp.d.ts +2739 -0
- package/dist/nextjs/api.js +350 -12
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/client.d.ts +28 -1
- package/dist/nextjs/client.js +24 -3
- package/dist/nextjs/client.js.map +1 -1
- package/dist/nextjs/server.d.ts +173 -3
- package/dist/nextjs/server.js +372 -10
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +3761 -414
- package/dist/server.js +5865 -1043
- package/dist/server.js.map +1 -1
- package/dist/{session-DTHahDQ9.d.ts → session-Dfwu5g2W.d.ts} +28 -1
- package/migrations/20260810112144_colorful_tomorrow_man/migration.sql +18 -0
- package/migrations/20260810112144_colorful_tomorrow_man/snapshot.json +3576 -0
- package/migrations/20260901091716_fine_arclight/migration.sql +21 -0
- package/migrations/20260901091716_fine_arclight/snapshot.json +3849 -0
- package/migrations/20260906155957_natural_moonstone/migration.sql +33 -0
- package/migrations/20260906155957_natural_moonstone/snapshot.json +4275 -0
- package/migrations/20260907020904_giant_eternals/migration.sql +21 -0
- package/migrations/20260907020904_giant_eternals/snapshot.json +4561 -0
- package/migrations/20260907044807_eminent_angel/migration.sql +2 -0
- package/migrations/20260907044807_eminent_angel/snapshot.json +4561 -0
- package/migrations/20260918083158_foamy_roughhouse/migration.sql +55 -0
- package/migrations/20260918083158_foamy_roughhouse/snapshot.json +5271 -0
- package/package.json +9 -6
- 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
|
-
|
|
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
|
package/dist/client.js.map
CHANGED
|
@@ -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;
|