@spfn/auth 0.3.0-beta.4 → 0.3.0-beta.6

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 CHANGED
@@ -154,6 +154,8 @@ real secret values out of band, never commit them.
154
154
  | `SPFN_AUTH_OAUTH_SUCCESS_URL` | `.env.server` | — | default `/auth/callback` |
155
155
  | `SPFN_AUTH_OAUTH_ERROR_URL` | `.env.server` | — | default `/auth/error?error={error}` |
156
156
  | `SPFN_AUTH_RESERVED_USERNAMES` / `_USERNAME_MIN_LENGTH` / `_USERNAME_MAX_LENGTH` | `.env.server` | — | username rules |
157
+ | `SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES` / `_SETUP_TTL_MINUTES` | `.env.server` | — | defaults `30` / `15` — see [Verified-email signup](#verified-email-signup) |
158
+ | `SPFN_AUTH_SIGNUP_CONFIRM_PATH` | `.env.server` | — | default `/signup/confirm`; the page in your app the emailed link opens |
157
159
  | `NEXT_PUBLIC_SPFN_API_URL` / `NEXT_PUBLIC_SPFN_APP_URL` | `.env.local` | — | browser-facing URLs for OAuth redirects |
158
160
 
159
161
  Read validated values via `import { env } from '@spfn/auth/config'` (a proxy validated at
@@ -178,6 +180,9 @@ routes use `.skip(['auth'])`; the rest require `Authorization: Bearer <client-si
178
180
  | `sendVerificationCode` | POST `/_auth/codes` | public | send 6-digit OTP |
179
181
  | `verifyCode` | POST `/_auth/codes/verify` | public | verify OTP → verification token |
180
182
  | `register` | POST `/_auth/register` | public | create user + register public key |
183
+ | `requestSignupLink` | POST `/_auth/signup/email` | public | email a one-time signup confirmation link — see [Verified-email signup](#verified-email-signup) |
184
+ | `confirmSignupLink` | POST `/_auth/signup/email/confirm` | public | exchange the link for a password-setup session |
185
+ | `completeSignup` | POST `/_auth/signup/password` | setup session | set the password, which creates the account and signs in |
181
186
  | `login` | POST `/_auth/login` | public | password login + new session key |
182
187
  | `logout` | POST `/_auth/logout` | yes | revoke current key |
183
188
  | `rotateKey` | POST `/_auth/keys/rotate` | yes | rotate public key before 90-day expiry |
@@ -205,6 +210,83 @@ sends the public key on register/login, signs request JWTs locally, and the serv
205
210
  with the stored public key (`keyId` carried in the JWT). The server never holds a private key.
206
211
  Keys expire after 90 days — rotate with `rotateKey`.
207
212
 
213
+ ### Verified-email signup
214
+
215
+ A second way in, alongside the six-digit code. The address is proven before a password
216
+ exists, so nothing is stored for someone who never confirms.
217
+
218
+ ```
219
+ request → a one-time link is emailed
220
+ confirm → the link becomes a short-lived, HttpOnly password-setup session
221
+ password → the account is created, the device registered, the user signed in
222
+ ```
223
+
224
+ The six-digit-code path (`sendVerificationCode` → `verifyCode` → `register`) is unchanged.
225
+ Offer whichever suits your product, or both.
226
+
227
+ **1 — request the link.** The response is identical whether or not the address already has
228
+ an account, so it cannot be used to probe for accounts. When one exists, the owner gets a
229
+ "you already have an account" notice instead of a usable link.
230
+
231
+ ```typescript
232
+ await authApi.requestSignupLink.call({
233
+ body: { email: 'user@example.com', returnPath: '/welcome' }, // returnPath optional
234
+ });
235
+ // → { success: true, expiresAt }
236
+ ```
237
+
238
+ Calling it again is how a resend works: it invalidates the previous link and any setup
239
+ session opened from it. `returnPath` must be a path inside your app — absolute URLs,
240
+ `//host`, and `..` are refused, so the link cannot become an open redirect.
241
+
242
+ **2 — the page the link opens.** The email points at a page in *your* app
243
+ (`SPFN_AUTH_SIGNUP_CONFIRM_PATH`, default `/signup/confirm`), not at an API route. That page
244
+ reads the token from the query string and posts it:
245
+
246
+ ```typescript
247
+ 'use client';
248
+
249
+ const token = useSearchParams().get('token');
250
+
251
+ const { email, returnPath } = await authApi.confirmSignupLink.call({ body: { token } });
252
+
253
+ // Drop the token from the URL so it does not linger in history or a Referer header.
254
+ window.history.replaceState({}, '', window.location.pathname);
255
+ ```
256
+
257
+ The setup session comes back as an HttpOnly cookie — the proxy interceptor moves it there
258
+ and strips it from the response body, so page script never holds it. Serve this page with
259
+ `Referrer-Policy: no-referrer`.
260
+
261
+ **3 — set the password.** This is the step that creates the account. The setup cookie
262
+ authorizes it; the device keypair is injected by the interceptor exactly as it is for
263
+ `register`.
264
+
265
+ ```typescript
266
+ await authApi.completeSignup.call({ body: { password } });
267
+ // → { userId, publicId, email } + session cookie, same as register
268
+ ```
269
+
270
+ Creating the user, registering the device key, and marking the setup session used all commit
271
+ together. A password that fails the strength policy leaves the session usable, so the user
272
+ retypes rather than requesting a fresh email.
273
+
274
+ **Settings.**
275
+
276
+ | Variable | Default | Meaning |
277
+ |----------|---------|---------|
278
+ | `SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES` | `30` | how long the emailed link works |
279
+ | `SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES` | `15` | how long the password-setup session works |
280
+ | `SPFN_AUTH_SIGNUP_CONFIRM_PATH` | `/signup/confirm` | the page in your app the link opens |
281
+
282
+ The link URL is built on `NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL`, the same resolution the
283
+ OAuth callbacks use. Delivery uses the `signup-link` template in `@spfn/notification` —
284
+ override it there to change the copy.
285
+
286
+ **What is stored.** Only SHA-256 hashes of the link token and the setup secret, in
287
+ `spfn_auth.signup_link_tokens`. Neither credential is recoverable from the database, and
288
+ both are one-time: a link opens one setup session, and a setup session sets one password.
289
+
208
290
  ### Registered devices (key management)
209
291
 
210
292
  Keys are per-device, so a login never revokes the previous key and they accumulate on purpose.
@@ -827,6 +909,8 @@ Notes:
827
909
  seeding in `initializeAuth()`.
828
910
  - OAuth signups have no client-typed fields unless you pass `metadata` at OAuth start — decide
829
911
  per channel (reject, or allow and collect during onboarding).
912
+ - `email` arrives trimmed and lower-cased, the same form the account is stored under, so a
913
+ denylist or domain allowlist keyed on the address is not walked past by capitalizing it.
830
914
  - On the `oauth` channel `email` is the provider-reported address and may be **unverified**
831
915
  (the created account then stores `email` as `null`). The context carries
832
916
  `emailVerified` — an email-based allow/block policy must check it before trusting `email`.
@@ -1239,6 +1323,23 @@ authorization.
1239
1323
  The environment, seeded on startup by `createAuthLifecycle()`. Seeded accounts are email
1240
1324
  verified, active, and required to change their password on first login.
1241
1325
 
1326
+ **Is `Foo@Example.com` the same account as `foo@example.com`?**
1327
+ Yes. Addresses are trimmed and lower-cased on the way in and on the way out, so one person
1328
+ who capitalizes differently on different days reaches one account instead of creating a
1329
+ second. Nothing else is folded — Gmail's dot and `+` rules are that provider's delivery
1330
+ behaviour, not an internet rule, and applying them would merge addresses other providers
1331
+ treat as different people.
1332
+
1333
+ `createAuthLifecycle()` brings existing rows into the same form on startup. If two accounts
1334
+ differ only by capitalization, both are left exactly as they are and their user ids are
1335
+ logged as an error: which one is the real account, and what becomes of the other's data, is
1336
+ not a question the package can answer for you. Until you resolve it, the mixed-case one
1337
+ cannot sign in.
1338
+
1339
+ Admin seeding is unaffected either way. It recognizes a configured admin in whatever form
1340
+ the address was stored, so an account the backfill has not reached is skipped rather than
1341
+ duplicated into a second privileged row holding the configured password.
1342
+
1242
1343
  ## Pitfalls & anti-patterns
1243
1344
 
1244
1345
  - **"relation \"auth.users\" does not exist" — tables come from bundled migrations, not push.**
@@ -214,6 +214,93 @@ declare function verifyCodeService(params: VerifyCodeParams): Promise<{
214
214
  verificationToken: string;
215
215
  }>;
216
216
 
217
+ /**
218
+ * @spfn/auth - Verified-Email Signup Service
219
+ *
220
+ * A signup where the address is proven before a password exists:
221
+ *
222
+ * request -> a one-time link is emailed
223
+ * confirm -> the link is exchanged for a short-lived password-setup session
224
+ * password -> the account is created, the device registered, the user signed in
225
+ *
226
+ * The link token and the setup secret are bearer credentials, so neither is ever
227
+ * stored. Only their SHA-256 hashes are, and lookup is by hash. A database dump
228
+ * therefore yields nothing that can be presented to either step.
229
+ *
230
+ * The six-digit-code registration path is untouched and remains the default; this
231
+ * is a second entry point to the same account creation, not a replacement.
232
+ */
233
+
234
+ /**
235
+ * Whether a return path can be handed back to the browser.
236
+ *
237
+ * Only a path within the app is allowed. The rejected shapes are the ones that
238
+ * turn a return path into an open redirect: an absolute URL, a protocol-relative
239
+ * `//host` that a browser reads as another origin, a backslash that some
240
+ * browsers normalize into a slash, and any `..` traversal.
241
+ */
242
+ declare function isSafeReturnPath(returnPath: string): boolean;
243
+ interface RequestSignupLinkParams {
244
+ email: string;
245
+ returnPath?: string;
246
+ }
247
+ interface RequestSignupLinkResult {
248
+ success: boolean;
249
+ expiresAt: string;
250
+ }
251
+ /**
252
+ * Step 1 — issue a confirmation link for an address.
253
+ *
254
+ * Answers identically whether or not the address already has an account. When it
255
+ * does, the owner gets a notice instead of a usable link, through the same
256
+ * dedupe window the six-digit-code path uses.
257
+ *
258
+ * Requesting again is how a resend works: every live link for the address is
259
+ * superseded first, so the newest link is the only one that opens, and any setup
260
+ * session already opened from an older link dies with it.
261
+ */
262
+ declare function requestSignupLinkService(params: RequestSignupLinkParams): Promise<RequestSignupLinkResult>;
263
+ interface ConfirmSignupLinkParams {
264
+ token: string;
265
+ }
266
+ interface ConfirmSignupLinkResult {
267
+ email: string;
268
+ returnPath: string | null;
269
+ /** Handed to the proxy interceptor, which moves it into an HttpOnly cookie. */
270
+ setupSecret: string;
271
+ setupExpiresAt: string;
272
+ }
273
+ /**
274
+ * Step 2 — exchange a link for a password-setup session.
275
+ *
276
+ * Nothing binds the row to a device or a browser, which is what lets someone
277
+ * request the link on a laptop and open it on a phone.
278
+ */
279
+ declare function confirmSignupLinkService(params: ConfirmSignupLinkParams): Promise<ConfirmSignupLinkResult>;
280
+ interface CompleteSignupParams {
281
+ setupSecret?: string;
282
+ password: string;
283
+ publicKey: string;
284
+ keyId: string;
285
+ fingerprint: string;
286
+ algorithm?: KeyAlgorithmType;
287
+ deviceName?: string;
288
+ platform?: KeyPlatformType;
289
+ metadata?: Record<string, unknown>;
290
+ }
291
+ /**
292
+ * Step 3 — set the password, which is what creates the account.
293
+ *
294
+ * Run under `Transactional()`: the user row, the device key and the completion
295
+ * mark commit together. A device-key failure must not leave an account nobody
296
+ * can sign into, and a completion mark must not survive a rolled-back account.
297
+ *
298
+ * A refusal that is the user's to fix — a weak password, an app policy that
299
+ * rejects the registration — leaves the setup session usable, so the fix is
300
+ * retyping the password rather than requesting a fresh email.
301
+ */
302
+ declare function completeSignupService(params: CompleteSignupParams): Promise<RegisterResult>;
303
+
217
304
  /**
218
305
  * @spfn/auth - Key Service
219
306
  *
@@ -814,6 +901,33 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
814
901
  platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
815
902
  }>;
816
903
  }, RegisterResult>;
904
+ requestSignupLink: _spfn_core_route.RouteDef<{
905
+ body: _sinclair_typebox.TObject<{
906
+ email: _sinclair_typebox.TString;
907
+ returnPath: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
908
+ }>;
909
+ }, {}, RequestSignupLinkResult>;
910
+ confirmSignupLink: _spfn_core_route.RouteDef<{
911
+ body: _sinclair_typebox.TObject<{
912
+ token: _sinclair_typebox.TString;
913
+ }>;
914
+ }, {}, ConfirmSignupLinkResult>;
915
+ completeSignup: _spfn_core_route.RouteDef<{
916
+ body: _sinclair_typebox.TObject<{
917
+ password: _sinclair_typebox.TString;
918
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
919
+ }>;
920
+ }, {
921
+ body: _sinclair_typebox.TObject<{
922
+ setupSecret: _sinclair_typebox.TString;
923
+ publicKey: _sinclair_typebox.TString;
924
+ keyId: _sinclair_typebox.TString;
925
+ fingerprint: _sinclair_typebox.TString;
926
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
927
+ deviceName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
928
+ platform: _sinclair_typebox.TOptional<_sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ios" | "android" | "web" | "desktop">[]>>;
929
+ }>;
930
+ }, RegisterResult>;
817
931
  login: _spfn_core_route.RouteDef<{
818
932
  body: _sinclair_typebox.TObject<{
819
933
  email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
@@ -1444,4 +1558,4 @@ declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
1444
1558
  */
1445
1559
  declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
1446
1560
 
1447
- export { type UnlinkNotifyResult as $, type AuthInitOptions as A, PasswordSchema as B, type ChangePasswordParams as C, DeviceNameSchema as D, EmailSchema as E, PhoneSchema as F, PlatformSchema as G, type RegisterParams as H, type IssueOneTimeTokenResult as I, type RegisterPublicKeyParams as J, type KeySummary as K, type LoginResult as L, type RevokeAllKeysParams as M, type NativeVerifyOptions as N, type OAuthStartResult as O, type PermissionConfig as P, type RevokeKeyParams as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RotateKeyParams as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type SendVerificationCodeParams as W, TargetTypeSchema as X, type UnlinkNotification as Y, UnlinkNotifyRejection as Z, type UnlinkNotifyRequest as _, type RegisterResult as a, VerificationPurposeSchema as a0, type VerifyCodeParams as a1, type VerifyCodeResult as a2, authenticate as a3, buildOAuthErrorUrl as a4, changePasswordService as a5, getEnabledOAuthProviders as a6, getGoogleAccessToken as a7, getOAuthProvider as a8, getRegisteredProviders as a9, isOAuthProviderEnabled as aa, issueOneTimeTokenService as ab, listKeysService as ac, loginService as ad, logoutService as ae, oauthCallbackService as af, oauthNativeService as ag, oauthStartService as ah, oauthUnlinkNotifyService as ai, optionalAuth as aj, registerOAuthProvider as ak, registerPublicKeyService as al, registerService as am, requireEnabledProvider as an, resolveAuthenticatedUser as ao, revokeAllKeysService as ap, revokeKeyService as aq, rotateKeyService as ar, runAuthProfile as as, selectAuthProfile as at, sendVerificationCodeService as au, verifyCodeService as av, verifyOneTimeTokenService as aw, type RotateKeyResult as b, type RevokeAllKeysResult as c, type OAuthNativeResult as d, type ProfileInfo as e, type AuthSession as f, PERMISSION_CATEGORIES as g, type PermissionCategory as h, VERIFICATION_TARGET_TYPES as i, type VerificationPurpose as j, type VerificationTargetType as k, type OAuthProvider as l, mainAuthRouter as m, type AuthContext as n, type AuthProfileOutcome as o, type AuthProfileVerifier as p, KEY_FINGERPRINT_PREFIX_LENGTH as q, type LoginParams as r, type LogoutParams as s, type NormalizedIdentity as t, type OAuthCallbackParams as u, type OAuthCallbackResult as v, type OAuthCodeExchangeOptions as w, type OAuthNativeParams as x, type OAuthStartParams as y, type OAuthTokens as z };
1561
+ export { type SendVerificationCodeParams as $, type AuthInitOptions as A, type OAuthCodeExchangeOptions as B, type ConfirmSignupLinkResult as C, DeviceNameSchema as D, EmailSchema as E, type OAuthNativeParams as F, type OAuthStartParams as G, type OAuthTokens as H, type IssueOneTimeTokenResult as I, PasswordSchema as J, type KeySummary as K, type LoginResult as L, PhoneSchema as M, type NativeVerifyOptions as N, type OAuthStartResult as O, type PermissionConfig as P, PlatformSchema as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RegisterParams as T, type UserProfile as U, VERIFICATION_PURPOSES as V, type RegisterPublicKeyParams as W, type RequestSignupLinkParams as X, type RevokeAllKeysParams as Y, type RevokeKeyParams as Z, type RotateKeyParams as _, type RegisterResult as a, TargetTypeSchema as a0, type UnlinkNotification as a1, UnlinkNotifyRejection as a2, type UnlinkNotifyRequest as a3, type UnlinkNotifyResult as a4, VerificationPurposeSchema as a5, type VerifyCodeParams as a6, type VerifyCodeResult as a7, authenticate as a8, buildOAuthErrorUrl as a9, rotateKeyService as aA, runAuthProfile as aB, selectAuthProfile as aC, sendVerificationCodeService as aD, verifyCodeService as aE, verifyOneTimeTokenService as aF, changePasswordService as aa, completeSignupService as ab, confirmSignupLinkService as ac, getEnabledOAuthProviders as ad, getGoogleAccessToken as ae, getOAuthProvider as af, getRegisteredProviders as ag, isOAuthProviderEnabled as ah, isSafeReturnPath as ai, issueOneTimeTokenService as aj, listKeysService as ak, loginService as al, logoutService as am, oauthCallbackService as an, oauthNativeService as ao, oauthStartService as ap, oauthUnlinkNotifyService as aq, optionalAuth as ar, registerOAuthProvider as as, registerPublicKeyService as at, registerService as au, requestSignupLinkService as av, requireEnabledProvider as aw, resolveAuthenticatedUser as ax, revokeAllKeysService as ay, revokeKeyService as az, type RequestSignupLinkResult as b, type RotateKeyResult as c, type RevokeAllKeysResult as d, type OAuthNativeResult as e, type ProfileInfo as f, type AuthSession as g, PERMISSION_CATEGORIES as h, type PermissionCategory as i, VERIFICATION_TARGET_TYPES as j, type VerificationPurpose as k, type VerificationTargetType as l, mainAuthRouter as m, type OAuthProvider as n, type AuthContext as o, type AuthProfileOutcome as p, type AuthProfileVerifier as q, type ChangePasswordParams as r, type CompleteSignupParams as s, type ConfirmSignupLinkParams as t, KEY_FINGERPRINT_PREFIX_LENGTH as u, type LoginParams as v, type LogoutParams as w, type NormalizedIdentity as x, type OAuthCallbackParams as y, type OAuthCallbackResult as z };
package/dist/config.d.ts CHANGED
@@ -195,6 +195,36 @@ declare const authEnvSchema: {
195
195
  } & {
196
196
  key: "SPFN_AUTH_USERNAME_MAX_LENGTH";
197
197
  };
198
+ SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES: {
199
+ description: string;
200
+ default: number;
201
+ required: boolean;
202
+ examples: number[];
203
+ type: "number";
204
+ validator: (value: string) => number;
205
+ } & {
206
+ key: "SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES";
207
+ };
208
+ SPFN_AUTH_SIGNUP_SETUP_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_SETUP_TTL_MINUTES";
217
+ };
218
+ SPFN_AUTH_SIGNUP_CONFIRM_PATH: {
219
+ description: string;
220
+ default: string;
221
+ required: boolean;
222
+ examples: string[];
223
+ type: "string";
224
+ validator: (value: string) => string;
225
+ } & {
226
+ key: "SPFN_AUTH_SIGNUP_CONFIRM_PATH";
227
+ };
198
228
  SPFN_API_URL: {
199
229
  description: string;
200
230
  default: string;
@@ -609,6 +639,36 @@ declare const env: _spfn_core_env.InferEnvType<{
609
639
  } & {
610
640
  key: "SPFN_AUTH_USERNAME_MAX_LENGTH";
611
641
  };
642
+ SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES: {
643
+ description: string;
644
+ default: number;
645
+ required: boolean;
646
+ examples: number[];
647
+ type: "number";
648
+ validator: (value: string) => number;
649
+ } & {
650
+ key: "SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES";
651
+ };
652
+ SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES: {
653
+ description: string;
654
+ default: number;
655
+ required: boolean;
656
+ examples: number[];
657
+ type: "number";
658
+ validator: (value: string) => number;
659
+ } & {
660
+ key: "SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES";
661
+ };
662
+ SPFN_AUTH_SIGNUP_CONFIRM_PATH: {
663
+ description: string;
664
+ default: string;
665
+ required: boolean;
666
+ examples: string[];
667
+ type: "string";
668
+ validator: (value: string) => string;
669
+ } & {
670
+ key: "SPFN_AUTH_SIGNUP_CONFIRM_PATH";
671
+ };
612
672
  SPFN_API_URL: {
613
673
  description: string;
614
674
  default: string;
package/dist/config.js CHANGED
@@ -201,6 +201,33 @@ var authEnvSchema = defineEnvSchema({
201
201
  })
202
202
  },
203
203
  // ============================================================================
204
+ // Verified-email signup
205
+ // ============================================================================
206
+ SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES: {
207
+ ...envNumber({
208
+ description: "How long an emailed signup confirmation link stays valid. Long enough to survive a mail delay, short enough that a link left in an inbox stops working.",
209
+ default: 30,
210
+ required: false,
211
+ examples: [15, 30, 60]
212
+ })
213
+ },
214
+ SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES: {
215
+ ...envNumber({
216
+ description: "How long the password-setup session opened by a confirmation link stays valid. Covers one sitting at the password form, not an abandoned tab.",
217
+ default: 15,
218
+ required: false,
219
+ examples: [10, 15, 30]
220
+ })
221
+ },
222
+ SPFN_AUTH_SIGNUP_CONFIRM_PATH: {
223
+ ...envString({
224
+ description: "App page the emailed confirmation link opens, as a path on {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}. The page reads the token from the query string and posts it to /_auth/signup/email/confirm; it is a page in your app, not an API route.",
225
+ default: "/signup/confirm",
226
+ required: false,
227
+ examples: ["/signup/confirm", "/auth/confirm", "/join/verify"]
228
+ })
229
+ },
230
+ // ============================================================================
204
231
  // API Configuration
205
232
  // ============================================================================
206
233
  SPFN_API_URL: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config/index.ts","../src/config/schema.ts"],"sourcesContent":["/**\n * Core Package Configuration\n *\n * @example\n * ```typescript\n * import { registry } from '@spfn/core/config';\n *\n * const env = registry.validate();\n * console.log(env.DB_POOL_MAX);\n * ```\n *\n * @module config\n */\n\nimport { createEnvRegistry } from '@spfn/core/env';\nimport { authEnvSchema } from './schema';\n\nexport { authEnvSchema as envSchema } from './schema';\n\n/**\n * Environment registry\n */\nconst registry = createEnvRegistry(authEnvSchema);\nexport const env = registry.validate();\n","/**\n * Auth Environment Variable Schema\n *\n * Centralized schema definition for all environment variables used in @spfn/auth.\n * This provides type safety, validation, and documentation for Auth configuration.\n *\n * @module config/schema\n */\n\nimport {\n defineEnvSchema,\n envString,\n envNumber,\n envBoolean,\n createSecureSecretParser,\n createPasswordParser,\n} from '@spfn/core/env';\n\n/**\n * Auth environment variable schema\n *\n * Defines all Auth environment variables with:\n * - Type information\n * - Default values\n * - Validation rules\n * - Documentation\n *\n * @example\n * ```typescript\n * import { envSchema } from '@spfn/auth/config';\n *\n * // Access schema information\n * console.log(envSchema.SPFN_AUTH_SESSION_SECRET.description);\n * console.log(envSchema.SPFN_AUTH_JWT_EXPIRES_IN.default);\n * ```\n */\nexport const authEnvSchema = defineEnvSchema({\n // ============================================================================\n // Session Configuration\n // ============================================================================\n SPFN_AUTH_SESSION_SECRET: {\n ...envString({\n description: 'Session encryption secret (minimum 32 characters for AES-256)',\n required: true,\n fallbackKeys: ['SESSION_SECRET'],\n validator: createSecureSecretParser({\n minLength: 32,\n minUniqueChars: 16,\n minEntropy: 3.5,\n }),\n sensitive: true,\n nextjs: true, // Required for Next.js RSC session validation\n examples: [\n 'my-super-secret-session-key-at-least-32-chars-long',\n 'use-a-cryptographically-secure-random-string-here',\n ],\n }),\n },\n\n SPFN_AUTH_SESSION_TTL: {\n ...envString({\n description: 'Session TTL (time to live) - supports duration strings like \\'7d\\', \\'12h\\', \\'45m\\'',\n default: '7d',\n required: false,\n nextjs: true, // May be needed for session validation in Next.js RSC\n examples: ['7d', '30d', '12h', '45m', '3600'],\n }),\n },\n\n // ============================================================================\n // JWT Configuration\n // ============================================================================\n SPFN_AUTH_JWT_SECRET: {\n ...envString({\n description: 'JWT signing secret for server-signed tokens (legacy mode)',\n default: 'dev-secret-key-change-in-production',\n required: false,\n examples: [\n 'your-jwt-secret-key-here',\n 'use-different-from-session-secret',\n ],\n }),\n },\n\n SPFN_AUTH_JWT_EXPIRES_IN: {\n ...envString({\n description: 'JWT token expiration time (e.g., \\'7d\\', \\'24h\\', \\'1h\\')',\n default: '7d',\n required: false,\n examples: ['7d', '24h', '1h', '30m'],\n }),\n },\n\n // ============================================================================\n // Security Configuration\n // ============================================================================\n SPFN_AUTH_COOKIE_SECURE: {\n ...envBoolean({\n description: 'Override cookie Secure flag. Defaults to NODE_ENV === \"production\". Set to false for HTTP-only environments (e.g. bastion over plain HTTP).',\n required: false,\n nextjs: true,\n examples: [true, false],\n }),\n },\n\n SPFN_AUTH_BCRYPT_SALT_ROUNDS: {\n ...envNumber({\n description: 'Bcrypt salt rounds (cost factor, higher = more secure but slower)',\n default: 12,\n required: false,\n examples: [10, 12, 14],\n }),\n key: 'SPFN_AUTH_BCRYPT_SALT_ROUNDS',\n },\n\n SPFN_AUTH_VERIFICATION_TOKEN_SECRET: {\n ...envString({\n description: 'Verification token secret for email verification, password reset, etc.',\n required: true,\n examples: [\n 'your-verification-token-secret',\n 'can-be-different-from-jwt-secret',\n ],\n }),\n },\n\n SPFN_AUTH_TOKEN_ENCRYPTION_KEYS: {\n ...envString({\n description: 'Backend-only OAuth token encryption keyring. Comma-separated <keyId>:<base64-encoded 32-byte key> entries; the first key encrypts new values and remaining keys decrypt during rotation.',\n required: false,\n sensitive: true,\n examples: [\n 'v2:<base64-encoded-32-byte-key>,v1:<previous-base64-encoded-32-byte-key>',\n ],\n }),\n },\n\n // ============================================================================\n // Admin Account Configuration\n // ============================================================================\n SPFN_AUTH_ADMIN_ACCOUNTS: {\n ...envString({\n description: 'JSON array of admin accounts (recommended for multiple admins)',\n required: false,\n examples: [\n '[{\"email\":\"admin@example.com\",\"password\":\"secure-pass\",\"role\":\"admin\"}]',\n '[{\"email\":\"super@example.com\",\"password\":\"pass1\",\"role\":\"superadmin\"},{\"email\":\"admin@example.com\",\"password\":\"pass2\",\"role\":\"admin\"}]',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAILS: {\n ...envString({\n description: 'Comma-separated list of admin emails (legacy CSV format)',\n required: false,\n examples: [\n 'admin@example.com,user@example.com',\n 'super@example.com,admin@example.com,user@example.com',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORDS: {\n ...envString({\n description: 'Comma-separated list of admin passwords (legacy CSV format)',\n required: false,\n examples: [\n 'admin-pass,user-pass',\n 'super-pass,admin-pass,user-pass',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_ROLES: {\n ...envString({\n description: 'Comma-separated list of admin roles (legacy CSV format)',\n required: false,\n examples: [\n 'admin,user',\n 'superadmin,admin,user',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAIL: {\n ...envString({\n description: 'Single admin email (simplest format)',\n required: false,\n examples: ['admin@example.com'],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORD: {\n ...envString({\n description: 'Single admin password (simplest format)',\n required: false,\n validator: createPasswordParser({\n minLength: 8,\n requireUppercase: true,\n requireLowercase: true,\n requireNumber: true,\n requireSpecial: true,\n }),\n sensitive: true,\n examples: ['SecureAdmin123!'],\n }),\n },\n\n // ============================================================================\n // Username Configuration\n // ============================================================================\n SPFN_AUTH_RESERVED_USERNAMES: {\n ...envString({\n description: 'Comma-separated list of reserved usernames that cannot be registered',\n required: false,\n default: 'admin,root,system,support,help,moderator,superadmin',\n examples: [\n 'admin,root,system,support,help',\n 'admin,root,system,support,help,moderator,superadmin,operator',\n ],\n }),\n },\n\n SPFN_AUTH_USERNAME_MIN_LENGTH: {\n ...envNumber({\n description: 'Minimum username length',\n default: 3,\n required: false,\n examples: [2, 3, 4],\n }),\n },\n\n SPFN_AUTH_USERNAME_MAX_LENGTH: {\n ...envNumber({\n description: 'Maximum username length',\n default: 30,\n required: false,\n examples: [20, 30, 50],\n }),\n },\n\n // ============================================================================\n // API Configuration\n // ============================================================================\n SPFN_API_URL: {\n ...envString({\n description: 'Internal API URL for server-to-server communication',\n default: 'http://localhost:8790',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_API_URL: {\n ...envString({\n description: 'Public-facing API URL used for browser-facing redirects. Falls back to SPFN_API_URL if not set.',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n SPFN_APP_URL: {\n ...envString({\n description: 'Next.js application URL (internal). Used for server-to-server communication.',\n default: 'http://localhost:3000',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_APP_URL: {\n ...envString({\n description: 'Public-facing Next.js app URL for browser redirects (e.g. OAuth redirect). Falls back to SPFN_APP_URL if not set.',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Google\n // ============================================================================\n SPFN_AUTH_GOOGLE_CLIENT_ID: {\n ...envString({\n description: 'Google OAuth 2.0 Client ID. When set, Google OAuth routes are automatically enabled.',\n required: false,\n examples: ['123456789-abc123.apps.googleusercontent.com'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_CLIENT_SECRET: {\n ...envString({\n description: 'Google OAuth 2.0 Client Secret',\n required: false,\n sensitive: true,\n examples: ['GOCSPX-abcdefghijklmnop'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_SCOPES: {\n ...envString({\n description: 'Comma-separated Google OAuth scopes. Defaults to \"email,profile\" if not set.',\n required: false,\n examples: [\n 'email,profile',\n 'email,profile,https://www.googleapis.com/auth/gmail.readonly',\n 'email,profile,https://www.googleapis.com/auth/calendar.readonly',\n ],\n }),\n },\n\n SPFN_AUTH_GOOGLE_REDIRECT_URI: {\n ...envString({\n description: 'Google OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/google/callback — the callback must return to the web app origin that set the oauth_csrf cookie (the app rewrites /_auth/:path* to the API). Set this explicitly only when the callback should hit a different host (e.g. the API host for the direct oauthStart flow).',\n required: false,\n examples: [\n 'https://app.example.com/_auth/oauth/google/callback',\n 'http://localhost:3000/_auth/oauth/google/callback',\n ],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Kakao\n // ============================================================================\n SPFN_AUTH_KAKAO_CLIENT_ID: {\n ...envString({\n description: 'Kakao Login REST API key. Used as the OAuth client_id.',\n required: false,\n examples: ['your-kakao-rest-api-key'],\n }),\n },\n\n SPFN_AUTH_KAKAO_CLIENT_SECRET: {\n ...envString({\n description: 'Kakao Login client secret. Required when the Kakao client-secret feature is enabled.',\n required: false,\n sensitive: true,\n examples: ['your-kakao-client-secret'],\n }),\n },\n\n SPFN_AUTH_KAKAO_ADMIN_KEY: {\n ...envString({\n description: 'Kakao app admin key. Required to verify the User Unlinked webhook (Authorization: KakaoAK header).',\n required: false,\n sensitive: true,\n examples: ['your-kakao-admin-key'],\n }),\n },\n\n SPFN_AUTH_KAKAO_SCOPES: {\n ...envString({\n description: 'Comma-separated Kakao consent scopes. Defaults to account_email.',\n required: false,\n examples: ['account_email'],\n }),\n },\n\n SPFN_AUTH_KAKAO_REDIRECT_URI: {\n ...envString({\n description: 'Kakao OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/kakao/callback.',\n required: false,\n examples: ['https://app.example.com/_auth/oauth/kakao/callback'],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Naver\n // ============================================================================\n SPFN_AUTH_NAVER_CLIENT_ID: {\n ...envString({\n description: 'Naver Login OAuth client ID.',\n required: false,\n examples: ['your-naver-client-id'],\n }),\n },\n\n SPFN_AUTH_NAVER_CLIENT_SECRET: {\n ...envString({\n description: 'Naver Login OAuth client secret.',\n required: false,\n sensitive: true,\n examples: ['your-naver-client-secret'],\n }),\n },\n\n SPFN_AUTH_NAVER_REDIRECT_URI: {\n ...envString({\n description: 'Naver OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/naver/callback.',\n required: false,\n examples: ['https://app.example.com/_auth/oauth/naver/callback'],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - GitHub\n // ============================================================================\n SPFN_AUTH_GITHUB_CLIENT_ID: {\n ...envString({\n description: 'GitHub OAuth app client ID. When set, GitHub OAuth routes are automatically enabled.',\n required: false,\n examples: ['Iv1.abc123def456'],\n }),\n },\n\n SPFN_AUTH_GITHUB_CLIENT_SECRET: {\n ...envString({\n description: 'GitHub OAuth app client secret.',\n required: false,\n sensitive: true,\n examples: ['your-github-client-secret'],\n }),\n },\n\n SPFN_AUTH_GITHUB_SCOPES: {\n ...envString({\n description: 'Comma-separated GitHub OAuth scopes. Defaults to \"read:user,user:email\".',\n required: false,\n examples: ['read:user,user:email'],\n }),\n },\n\n SPFN_AUTH_GITHUB_REDIRECT_URI: {\n ...envString({\n description: 'GitHub OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/github/callback.',\n required: false,\n examples: ['https://app.example.com/_auth/oauth/github/callback'],\n }),\n },\n\n // ============================================================================\n // Native Social Login (mobile/web id_token verification)\n //\n // 네이티브 SDK가 받은 id_token을 서버가 JWKS로 검증하는 경로 전용 설정.\n // authorization code 교환을 하지 않으므로 client secret이 필요 없다.\n // audience(aud)로 허용할 client id 목록만 지정한다.\n // ============================================================================\n SPFN_AUTH_GOOGLE_NATIVE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Google client IDs accepted as id_token audience for native sign-in (iOS, Android, web). When set, Google native sign-in is enabled. SPFN_AUTH_GOOGLE_CLIENT_ID is also accepted automatically.',\n required: false,\n examples: [\n '123-ios.apps.googleusercontent.com,123-android.apps.googleusercontent.com',\n ],\n }),\n },\n\n SPFN_AUTH_APPLE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Apple client IDs accepted as id_token audience for native sign-in (iOS bundle ID, web/Android Services ID). When set, Apple native sign-in is enabled.',\n required: false,\n examples: [\n 'com.example.app,com.example.app.service',\n ],\n }),\n },\n\n SPFN_AUTH_KAKAO_NATIVE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Kakao app keys accepted as id_token audience for native sign-in (native app key). SPFN_AUTH_KAKAO_CLIENT_ID (REST API key) is also accepted automatically, so native sign-in is available when either variable is set. Requires OpenID Connect to be enabled in the Kakao developer console.',\n required: false,\n examples: [\n 'your-kakao-native-app-key',\n ],\n }),\n },\n\n SPFN_AUTH_NAVER_NATIVE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Naver client IDs accepted as id_token audience for native sign-in. SPFN_AUTH_NAVER_CLIENT_ID is also accepted automatically, and one Naver application has a single client ID covering web and app environments — set this only when the app uses a separate application.',\n required: false,\n examples: [\n 'your-naver-app-client-id',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_SUCCESS_URL: {\n ...envString({\n description: 'OAuth callback page URL. This page should use OAuthCallback component to finalize session.',\n required: false,\n default: '/auth/callback',\n examples: [\n '/auth/callback',\n 'https://app.example.com/auth/callback',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_ERROR_URL: {\n ...envString({\n description: 'URL to redirect after OAuth error. Use {error} placeholder for error message.',\n required: false,\n default: '/auth/error?error={error}',\n examples: [\n 'https://app.example.com/auth/error?error={error}',\n 'http://localhost:3000/auth/error?error={error}',\n ],\n }),\n },\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/config/index.ts","../src/config/schema.ts"],"sourcesContent":["/**\n * Core Package Configuration\n *\n * @example\n * ```typescript\n * import { registry } from '@spfn/core/config';\n *\n * const env = registry.validate();\n * console.log(env.DB_POOL_MAX);\n * ```\n *\n * @module config\n */\n\nimport { createEnvRegistry } from '@spfn/core/env';\nimport { authEnvSchema } from './schema';\n\nexport { authEnvSchema as envSchema } from './schema';\n\n/**\n * Environment registry\n */\nconst registry = createEnvRegistry(authEnvSchema);\nexport const env = registry.validate();\n","/**\n * Auth Environment Variable Schema\n *\n * Centralized schema definition for all environment variables used in @spfn/auth.\n * This provides type safety, validation, and documentation for Auth configuration.\n *\n * @module config/schema\n */\n\nimport {\n defineEnvSchema,\n envString,\n envNumber,\n envBoolean,\n createSecureSecretParser,\n createPasswordParser,\n} from '@spfn/core/env';\n\n/**\n * Auth environment variable schema\n *\n * Defines all Auth environment variables with:\n * - Type information\n * - Default values\n * - Validation rules\n * - Documentation\n *\n * @example\n * ```typescript\n * import { envSchema } from '@spfn/auth/config';\n *\n * // Access schema information\n * console.log(envSchema.SPFN_AUTH_SESSION_SECRET.description);\n * console.log(envSchema.SPFN_AUTH_JWT_EXPIRES_IN.default);\n * ```\n */\nexport const authEnvSchema = defineEnvSchema({\n // ============================================================================\n // Session Configuration\n // ============================================================================\n SPFN_AUTH_SESSION_SECRET: {\n ...envString({\n description: 'Session encryption secret (minimum 32 characters for AES-256)',\n required: true,\n fallbackKeys: ['SESSION_SECRET'],\n validator: createSecureSecretParser({\n minLength: 32,\n minUniqueChars: 16,\n minEntropy: 3.5,\n }),\n sensitive: true,\n nextjs: true, // Required for Next.js RSC session validation\n examples: [\n 'my-super-secret-session-key-at-least-32-chars-long',\n 'use-a-cryptographically-secure-random-string-here',\n ],\n }),\n },\n\n SPFN_AUTH_SESSION_TTL: {\n ...envString({\n description: 'Session TTL (time to live) - supports duration strings like \\'7d\\', \\'12h\\', \\'45m\\'',\n default: '7d',\n required: false,\n nextjs: true, // May be needed for session validation in Next.js RSC\n examples: ['7d', '30d', '12h', '45m', '3600'],\n }),\n },\n\n // ============================================================================\n // JWT Configuration\n // ============================================================================\n SPFN_AUTH_JWT_SECRET: {\n ...envString({\n description: 'JWT signing secret for server-signed tokens (legacy mode)',\n default: 'dev-secret-key-change-in-production',\n required: false,\n examples: [\n 'your-jwt-secret-key-here',\n 'use-different-from-session-secret',\n ],\n }),\n },\n\n SPFN_AUTH_JWT_EXPIRES_IN: {\n ...envString({\n description: 'JWT token expiration time (e.g., \\'7d\\', \\'24h\\', \\'1h\\')',\n default: '7d',\n required: false,\n examples: ['7d', '24h', '1h', '30m'],\n }),\n },\n\n // ============================================================================\n // Security Configuration\n // ============================================================================\n SPFN_AUTH_COOKIE_SECURE: {\n ...envBoolean({\n description: 'Override cookie Secure flag. Defaults to NODE_ENV === \"production\". Set to false for HTTP-only environments (e.g. bastion over plain HTTP).',\n required: false,\n nextjs: true,\n examples: [true, false],\n }),\n },\n\n SPFN_AUTH_BCRYPT_SALT_ROUNDS: {\n ...envNumber({\n description: 'Bcrypt salt rounds (cost factor, higher = more secure but slower)',\n default: 12,\n required: false,\n examples: [10, 12, 14],\n }),\n key: 'SPFN_AUTH_BCRYPT_SALT_ROUNDS',\n },\n\n SPFN_AUTH_VERIFICATION_TOKEN_SECRET: {\n ...envString({\n description: 'Verification token secret for email verification, password reset, etc.',\n required: true,\n examples: [\n 'your-verification-token-secret',\n 'can-be-different-from-jwt-secret',\n ],\n }),\n },\n\n SPFN_AUTH_TOKEN_ENCRYPTION_KEYS: {\n ...envString({\n description: 'Backend-only OAuth token encryption keyring. Comma-separated <keyId>:<base64-encoded 32-byte key> entries; the first key encrypts new values and remaining keys decrypt during rotation.',\n required: false,\n sensitive: true,\n examples: [\n 'v2:<base64-encoded-32-byte-key>,v1:<previous-base64-encoded-32-byte-key>',\n ],\n }),\n },\n\n // ============================================================================\n // Admin Account Configuration\n // ============================================================================\n SPFN_AUTH_ADMIN_ACCOUNTS: {\n ...envString({\n description: 'JSON array of admin accounts (recommended for multiple admins)',\n required: false,\n examples: [\n '[{\"email\":\"admin@example.com\",\"password\":\"secure-pass\",\"role\":\"admin\"}]',\n '[{\"email\":\"super@example.com\",\"password\":\"pass1\",\"role\":\"superadmin\"},{\"email\":\"admin@example.com\",\"password\":\"pass2\",\"role\":\"admin\"}]',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAILS: {\n ...envString({\n description: 'Comma-separated list of admin emails (legacy CSV format)',\n required: false,\n examples: [\n 'admin@example.com,user@example.com',\n 'super@example.com,admin@example.com,user@example.com',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORDS: {\n ...envString({\n description: 'Comma-separated list of admin passwords (legacy CSV format)',\n required: false,\n examples: [\n 'admin-pass,user-pass',\n 'super-pass,admin-pass,user-pass',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_ROLES: {\n ...envString({\n description: 'Comma-separated list of admin roles (legacy CSV format)',\n required: false,\n examples: [\n 'admin,user',\n 'superadmin,admin,user',\n ],\n }),\n },\n\n SPFN_AUTH_ADMIN_EMAIL: {\n ...envString({\n description: 'Single admin email (simplest format)',\n required: false,\n examples: ['admin@example.com'],\n }),\n },\n\n SPFN_AUTH_ADMIN_PASSWORD: {\n ...envString({\n description: 'Single admin password (simplest format)',\n required: false,\n validator: createPasswordParser({\n minLength: 8,\n requireUppercase: true,\n requireLowercase: true,\n requireNumber: true,\n requireSpecial: true,\n }),\n sensitive: true,\n examples: ['SecureAdmin123!'],\n }),\n },\n\n // ============================================================================\n // Username Configuration\n // ============================================================================\n SPFN_AUTH_RESERVED_USERNAMES: {\n ...envString({\n description: 'Comma-separated list of reserved usernames that cannot be registered',\n required: false,\n default: 'admin,root,system,support,help,moderator,superadmin',\n examples: [\n 'admin,root,system,support,help',\n 'admin,root,system,support,help,moderator,superadmin,operator',\n ],\n }),\n },\n\n SPFN_AUTH_USERNAME_MIN_LENGTH: {\n ...envNumber({\n description: 'Minimum username length',\n default: 3,\n required: false,\n examples: [2, 3, 4],\n }),\n },\n\n SPFN_AUTH_USERNAME_MAX_LENGTH: {\n ...envNumber({\n description: 'Maximum username length',\n default: 30,\n required: false,\n examples: [20, 30, 50],\n }),\n },\n\n // ============================================================================\n // Verified-email signup\n // ============================================================================\n SPFN_AUTH_SIGNUP_LINK_TTL_MINUTES: {\n ...envNumber({\n description: 'How long an emailed signup confirmation link stays valid. Long enough to survive a mail delay, short enough that a link left in an inbox stops working.',\n default: 30,\n required: false,\n examples: [15, 30, 60],\n }),\n },\n\n SPFN_AUTH_SIGNUP_SETUP_TTL_MINUTES: {\n ...envNumber({\n description: 'How long the password-setup session opened by a confirmation link stays valid. Covers one sitting at the password form, not an abandoned tab.',\n default: 15,\n required: false,\n examples: [10, 15, 30],\n }),\n },\n\n SPFN_AUTH_SIGNUP_CONFIRM_PATH: {\n ...envString({\n description: 'App page the emailed confirmation link opens, as a path on {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}. The page reads the token from the query string and posts it to /_auth/signup/email/confirm; it is a page in your app, not an API route.',\n default: '/signup/confirm',\n required: false,\n examples: ['/signup/confirm', '/auth/confirm', '/join/verify'],\n }),\n },\n\n // ============================================================================\n // API Configuration\n // ============================================================================\n SPFN_API_URL: {\n ...envString({\n description: 'Internal API URL for server-to-server communication',\n default: 'http://localhost:8790',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_API_URL: {\n ...envString({\n description: 'Public-facing API URL used for browser-facing redirects. Falls back to SPFN_API_URL if not set.',\n required: false,\n examples: [\n 'https://api.example.com',\n 'http://localhost:8790',\n ],\n }),\n },\n\n SPFN_APP_URL: {\n ...envString({\n description: 'Next.js application URL (internal). Used for server-to-server communication.',\n default: 'http://localhost:3000',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n NEXT_PUBLIC_SPFN_APP_URL: {\n ...envString({\n description: 'Public-facing Next.js app URL for browser redirects (e.g. OAuth redirect). Falls back to SPFN_APP_URL if not set.',\n required: false,\n examples: [\n 'https://app.example.com',\n 'http://localhost:3000',\n ],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Google\n // ============================================================================\n SPFN_AUTH_GOOGLE_CLIENT_ID: {\n ...envString({\n description: 'Google OAuth 2.0 Client ID. When set, Google OAuth routes are automatically enabled.',\n required: false,\n examples: ['123456789-abc123.apps.googleusercontent.com'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_CLIENT_SECRET: {\n ...envString({\n description: 'Google OAuth 2.0 Client Secret',\n required: false,\n sensitive: true,\n examples: ['GOCSPX-abcdefghijklmnop'],\n }),\n },\n\n SPFN_AUTH_GOOGLE_SCOPES: {\n ...envString({\n description: 'Comma-separated Google OAuth scopes. Defaults to \"email,profile\" if not set.',\n required: false,\n examples: [\n 'email,profile',\n 'email,profile,https://www.googleapis.com/auth/gmail.readonly',\n 'email,profile,https://www.googleapis.com/auth/calendar.readonly',\n ],\n }),\n },\n\n SPFN_AUTH_GOOGLE_REDIRECT_URI: {\n ...envString({\n description: 'Google OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/google/callback — the callback must return to the web app origin that set the oauth_csrf cookie (the app rewrites /_auth/:path* to the API). Set this explicitly only when the callback should hit a different host (e.g. the API host for the direct oauthStart flow).',\n required: false,\n examples: [\n 'https://app.example.com/_auth/oauth/google/callback',\n 'http://localhost:3000/_auth/oauth/google/callback',\n ],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Kakao\n // ============================================================================\n SPFN_AUTH_KAKAO_CLIENT_ID: {\n ...envString({\n description: 'Kakao Login REST API key. Used as the OAuth client_id.',\n required: false,\n examples: ['your-kakao-rest-api-key'],\n }),\n },\n\n SPFN_AUTH_KAKAO_CLIENT_SECRET: {\n ...envString({\n description: 'Kakao Login client secret. Required when the Kakao client-secret feature is enabled.',\n required: false,\n sensitive: true,\n examples: ['your-kakao-client-secret'],\n }),\n },\n\n SPFN_AUTH_KAKAO_ADMIN_KEY: {\n ...envString({\n description: 'Kakao app admin key. Required to verify the User Unlinked webhook (Authorization: KakaoAK header).',\n required: false,\n sensitive: true,\n examples: ['your-kakao-admin-key'],\n }),\n },\n\n SPFN_AUTH_KAKAO_SCOPES: {\n ...envString({\n description: 'Comma-separated Kakao consent scopes. Defaults to account_email.',\n required: false,\n examples: ['account_email'],\n }),\n },\n\n SPFN_AUTH_KAKAO_REDIRECT_URI: {\n ...envString({\n description: 'Kakao OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/kakao/callback.',\n required: false,\n examples: ['https://app.example.com/_auth/oauth/kakao/callback'],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - Naver\n // ============================================================================\n SPFN_AUTH_NAVER_CLIENT_ID: {\n ...envString({\n description: 'Naver Login OAuth client ID.',\n required: false,\n examples: ['your-naver-client-id'],\n }),\n },\n\n SPFN_AUTH_NAVER_CLIENT_SECRET: {\n ...envString({\n description: 'Naver Login OAuth client secret.',\n required: false,\n sensitive: true,\n examples: ['your-naver-client-secret'],\n }),\n },\n\n SPFN_AUTH_NAVER_REDIRECT_URI: {\n ...envString({\n description: 'Naver OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/naver/callback.',\n required: false,\n examples: ['https://app.example.com/_auth/oauth/naver/callback'],\n }),\n },\n\n // ============================================================================\n // OAuth Configuration - GitHub\n // ============================================================================\n SPFN_AUTH_GITHUB_CLIENT_ID: {\n ...envString({\n description: 'GitHub OAuth app client ID. When set, GitHub OAuth routes are automatically enabled.',\n required: false,\n examples: ['Iv1.abc123def456'],\n }),\n },\n\n SPFN_AUTH_GITHUB_CLIENT_SECRET: {\n ...envString({\n description: 'GitHub OAuth app client secret.',\n required: false,\n sensitive: true,\n examples: ['your-github-client-secret'],\n }),\n },\n\n SPFN_AUTH_GITHUB_SCOPES: {\n ...envString({\n description: 'Comma-separated GitHub OAuth scopes. Defaults to \"read:user,user:email\".',\n required: false,\n examples: ['read:user,user:email'],\n }),\n },\n\n SPFN_AUTH_GITHUB_REDIRECT_URI: {\n ...envString({\n description: 'GitHub OAuth callback URL. Defaults to {NEXT_PUBLIC_SPFN_APP_URL || SPFN_APP_URL}/_auth/oauth/github/callback.',\n required: false,\n examples: ['https://app.example.com/_auth/oauth/github/callback'],\n }),\n },\n\n // ============================================================================\n // Native Social Login (mobile/web id_token verification)\n //\n // 네이티브 SDK가 받은 id_token을 서버가 JWKS로 검증하는 경로 전용 설정.\n // authorization code 교환을 하지 않으므로 client secret이 필요 없다.\n // audience(aud)로 허용할 client id 목록만 지정한다.\n // ============================================================================\n SPFN_AUTH_GOOGLE_NATIVE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Google client IDs accepted as id_token audience for native sign-in (iOS, Android, web). When set, Google native sign-in is enabled. SPFN_AUTH_GOOGLE_CLIENT_ID is also accepted automatically.',\n required: false,\n examples: [\n '123-ios.apps.googleusercontent.com,123-android.apps.googleusercontent.com',\n ],\n }),\n },\n\n SPFN_AUTH_APPLE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Apple client IDs accepted as id_token audience for native sign-in (iOS bundle ID, web/Android Services ID). When set, Apple native sign-in is enabled.',\n required: false,\n examples: [\n 'com.example.app,com.example.app.service',\n ],\n }),\n },\n\n SPFN_AUTH_KAKAO_NATIVE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Kakao app keys accepted as id_token audience for native sign-in (native app key). SPFN_AUTH_KAKAO_CLIENT_ID (REST API key) is also accepted automatically, so native sign-in is available when either variable is set. Requires OpenID Connect to be enabled in the Kakao developer console.',\n required: false,\n examples: [\n 'your-kakao-native-app-key',\n ],\n }),\n },\n\n SPFN_AUTH_NAVER_NATIVE_CLIENT_IDS: {\n ...envString({\n description: 'Comma-separated Naver client IDs accepted as id_token audience for native sign-in. SPFN_AUTH_NAVER_CLIENT_ID is also accepted automatically, and one Naver application has a single client ID covering web and app environments — set this only when the app uses a separate application.',\n required: false,\n examples: [\n 'your-naver-app-client-id',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_SUCCESS_URL: {\n ...envString({\n description: 'OAuth callback page URL. This page should use OAuthCallback component to finalize session.',\n required: false,\n default: '/auth/callback',\n examples: [\n '/auth/callback',\n 'https://app.example.com/auth/callback',\n ],\n }),\n },\n\n SPFN_AUTH_OAUTH_ERROR_URL: {\n ...envString({\n description: 'URL to redirect after OAuth error. Use {error} placeholder for error message.',\n required: false,\n default: '/auth/error?error={error}',\n examples: [\n 'https://app.example.com/auth/error?error={error}',\n 'http://localhost:3000/auth/error?error={error}',\n ],\n }),\n },\n});\n"],"mappings":"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","names":[]}
package/dist/errors.d.ts CHANGED
@@ -244,6 +244,39 @@ declare class NativeSignInUnsupportedError extends ValidationError {
244
244
  details?: Record<string, any>;
245
245
  });
246
246
  }
247
+ /**
248
+ * Invalid Signup Link Error (400)
249
+ *
250
+ * Thrown when an emailed signup confirmation link is unknown, expired, already
251
+ * consumed, or superseded by a newer request for the same address.
252
+ *
253
+ * One error for all four states, on purpose. Distinguishing "expired" from
254
+ * "unknown" tells a caller holding a random token whether it named a real
255
+ * pending signup, which is exactly the enumeration the request step avoids. The
256
+ * specific reason is logged.
257
+ */
258
+ declare class InvalidSignupLinkError extends ValidationError {
259
+ constructor(data?: {
260
+ message?: string;
261
+ details?: Record<string, any>;
262
+ });
263
+ }
264
+ /**
265
+ * Invalid Signup Setup Session Error (401)
266
+ *
267
+ * Thrown when the password-setup session backing a verified-email signup is
268
+ * missing, unknown, expired, superseded or already used.
269
+ *
270
+ * One error for every one of those, on purpose: telling a caller which of them
271
+ * applies tells them whether an address is mid-signup, which is the same
272
+ * enumeration the request step is careful not to leak.
273
+ */
274
+ declare class InvalidSignupSetupSessionError extends UnauthorizedError {
275
+ constructor(data?: {
276
+ message?: string;
277
+ details?: Record<string, any>;
278
+ });
279
+ }
247
280
  /**
248
281
  * Unverified Email Link Error (400)
249
282
  *
@@ -356,6 +389,10 @@ type authErrors_InvalidCredentialsError = InvalidCredentialsError;
356
389
  declare const authErrors_InvalidCredentialsError: typeof InvalidCredentialsError;
357
390
  type authErrors_InvalidKeyFingerprintError = InvalidKeyFingerprintError;
358
391
  declare const authErrors_InvalidKeyFingerprintError: typeof InvalidKeyFingerprintError;
392
+ type authErrors_InvalidSignupLinkError = InvalidSignupLinkError;
393
+ declare const authErrors_InvalidSignupLinkError: typeof InvalidSignupLinkError;
394
+ type authErrors_InvalidSignupSetupSessionError = InvalidSignupSetupSessionError;
395
+ declare const authErrors_InvalidSignupSetupSessionError: typeof InvalidSignupSetupSessionError;
359
396
  type authErrors_InvalidSocialTokenError = InvalidSocialTokenError;
360
397
  declare const authErrors_InvalidSocialTokenError: typeof InvalidSocialTokenError;
361
398
  type authErrors_InvalidTokenError = InvalidTokenError;
@@ -389,7 +426,7 @@ declare const authErrors_VerificationTokenPurposeMismatchError: typeof Verificat
389
426
  type authErrors_VerificationTokenTargetMismatchError = VerificationTokenTargetMismatchError;
390
427
  declare const authErrors_VerificationTokenTargetMismatchError: typeof VerificationTokenTargetMismatchError;
391
428
  declare namespace authErrors {
392
- export { authErrors_AccountAlreadyExistsError as AccountAlreadyExistsError, authErrors_AccountDisabledError as AccountDisabledError, authErrors_AccountPendingDeletionError as AccountPendingDeletionError, authErrors_DeletionAlreadyRequestedError as DeletionAlreadyRequestedError, authErrors_DeletionNotRequestedError as DeletionNotRequestedError, authErrors_ImmediateDeletionNotAllowedError as ImmediateDeletionNotAllowedError, authErrors_InsufficientPermissionsError as InsufficientPermissionsError, authErrors_InsufficientRoleError as InsufficientRoleError, authErrors_InvalidCredentialsError as InvalidCredentialsError, authErrors_InvalidKeyFingerprintError as InvalidKeyFingerprintError, authErrors_InvalidSocialTokenError as InvalidSocialTokenError, authErrors_InvalidTokenError as InvalidTokenError, authErrors_InvalidVerificationCodeError as InvalidVerificationCodeError, authErrors_InvalidVerificationTokenError as InvalidVerificationTokenError, authErrors_KeyExpiredError as KeyExpiredError, authErrors_KeyIdAlreadyRegisteredError as KeyIdAlreadyRegisteredError, authErrors_KeyNotFoundError as KeyNotFoundError, authErrors_NativeSignInUnsupportedError as NativeSignInUnsupportedError, authErrors_NonceKeyBindingError as NonceKeyBindingError, authErrors_RegistrationRejectedError as RegistrationRejectedError, authErrors_ReservedUsernameError as ReservedUsernameError, authErrors_TokenExpiredError as TokenExpiredError, authErrors_UnverifiedEmailLinkError as UnverifiedEmailLinkError, authErrors_UsernameAlreadyTakenError as UsernameAlreadyTakenError, authErrors_VerificationTokenPurposeMismatchError as VerificationTokenPurposeMismatchError, authErrors_VerificationTokenTargetMismatchError as VerificationTokenTargetMismatchError };
429
+ export { authErrors_AccountAlreadyExistsError as AccountAlreadyExistsError, authErrors_AccountDisabledError as AccountDisabledError, authErrors_AccountPendingDeletionError as AccountPendingDeletionError, authErrors_DeletionAlreadyRequestedError as DeletionAlreadyRequestedError, authErrors_DeletionNotRequestedError as DeletionNotRequestedError, authErrors_ImmediateDeletionNotAllowedError as ImmediateDeletionNotAllowedError, authErrors_InsufficientPermissionsError as InsufficientPermissionsError, authErrors_InsufficientRoleError as InsufficientRoleError, authErrors_InvalidCredentialsError as InvalidCredentialsError, authErrors_InvalidKeyFingerprintError as InvalidKeyFingerprintError, authErrors_InvalidSignupLinkError as InvalidSignupLinkError, authErrors_InvalidSignupSetupSessionError as InvalidSignupSetupSessionError, authErrors_InvalidSocialTokenError as InvalidSocialTokenError, authErrors_InvalidTokenError as InvalidTokenError, authErrors_InvalidVerificationCodeError as InvalidVerificationCodeError, authErrors_InvalidVerificationTokenError as InvalidVerificationTokenError, authErrors_KeyExpiredError as KeyExpiredError, authErrors_KeyIdAlreadyRegisteredError as KeyIdAlreadyRegisteredError, authErrors_KeyNotFoundError as KeyNotFoundError, authErrors_NativeSignInUnsupportedError as NativeSignInUnsupportedError, authErrors_NonceKeyBindingError as NonceKeyBindingError, authErrors_RegistrationRejectedError as RegistrationRejectedError, authErrors_ReservedUsernameError as ReservedUsernameError, authErrors_TokenExpiredError as TokenExpiredError, authErrors_UnverifiedEmailLinkError as UnverifiedEmailLinkError, authErrors_UsernameAlreadyTakenError as UsernameAlreadyTakenError, authErrors_VerificationTokenPurposeMismatchError as VerificationTokenPurposeMismatchError, authErrors_VerificationTokenTargetMismatchError as VerificationTokenTargetMismatchError };
393
430
  }
394
431
 
395
432
  /**
@@ -398,4 +435,4 @@ declare namespace authErrors {
398
435
 
399
436
  declare const authErrorRegistry: ErrorRegistry;
400
437
 
401
- export { AccountAlreadyExistsError, AccountDisabledError, AccountPendingDeletionError, authErrors as AuthError, DeletionAlreadyRequestedError, DeletionNotRequestedError, ImmediateDeletionNotAllowedError, InsufficientPermissionsError, InsufficientRoleError, InvalidCredentialsError, InvalidKeyFingerprintError, InvalidSocialTokenError, InvalidTokenError, InvalidVerificationCodeError, InvalidVerificationTokenError, KeyExpiredError, KeyIdAlreadyRegisteredError, KeyNotFoundError, NativeSignInUnsupportedError, NonceKeyBindingError, RegistrationRejectedError, ReservedUsernameError, TokenExpiredError, UnverifiedEmailLinkError, UsernameAlreadyTakenError, VerificationTokenPurposeMismatchError, VerificationTokenTargetMismatchError, authErrorRegistry };
438
+ export { AccountAlreadyExistsError, AccountDisabledError, AccountPendingDeletionError, authErrors as AuthError, DeletionAlreadyRequestedError, DeletionNotRequestedError, ImmediateDeletionNotAllowedError, InsufficientPermissionsError, InsufficientRoleError, InvalidCredentialsError, InvalidKeyFingerprintError, InvalidSignupLinkError, InvalidSignupSetupSessionError, InvalidSocialTokenError, InvalidTokenError, InvalidVerificationCodeError, InvalidVerificationTokenError, KeyExpiredError, KeyIdAlreadyRegisteredError, KeyNotFoundError, NativeSignInUnsupportedError, NonceKeyBindingError, RegistrationRejectedError, ReservedUsernameError, TokenExpiredError, UnverifiedEmailLinkError, UsernameAlreadyTakenError, VerificationTokenPurposeMismatchError, VerificationTokenTargetMismatchError, authErrorRegistry };