From c63006fbdd7debb8a904f0a3929c0bc0b99b07ef Mon Sep 17 00:00:00 2001 From: Manu MA Date: Sat, 22 Aug 2026 13:00:44 +0200 Subject: [PATCH] feat(auth): introduce email verification policy configuration - Added `AUTH_REQUIRE_EMAIL_VERIFICATION` environment variable to declare email verification policy for password signups across all environments, including production. - Updated documentation to reflect the new email verification policy and its implications for signup processes. - Enhanced the auth configuration to support the new policy, allowing for more granular control over email verification requirements. - Implemented tests to ensure the correct behavior of the email verification policy in various environments. --- .agents/skills/authentication/SKILL.md | 1 + .../auth-require-email-verification-config.md | 13 +++ .changeset/quiet-vite-rollup-options-alias.md | 5 ++ docs/environment-variables.md | 65 +++++++------- packages/core/docs/content/authentication.mdx | 61 ++++++++----- .../docs/content/environment-variables.mdx | 1 + .../content/locales/ar-SA/authentication.mdx | 19 +++++ .../content/locales/de-DE/authentication.mdx | 22 +++++ .../content/locales/es-ES/authentication.mdx | 21 +++++ .../content/locales/fr-FR/authentication.mdx | 21 +++++ .../content/locales/hi-IN/authentication.mdx | 20 +++++ .../content/locales/ja-JP/authentication.mdx | 19 +++++ .../content/locales/ko-KR/authentication.mdx | 19 +++++ .../content/locales/pt-BR/authentication.mdx | 21 +++++ .../content/locales/zh-CN/authentication.mdx | 17 ++++ .../content/locales/zh-TW/authentication.mdx | 17 ++++ packages/core/src/app-config/auth.ts | 7 ++ packages/core/src/server/auth.spec.ts | 85 +++++++++++++++++++ .../core/src/server/better-auth-instance.ts | 14 +++ packages/core/src/vite/client.spec.ts | 32 +++++++ packages/core/src/vite/client.ts | 13 ++- scripts/guard-env-documentation.ts | 1 + 22 files changed, 439 insertions(+), 55 deletions(-) create mode 100644 .changeset/auth-require-email-verification-config.md create mode 100644 .changeset/quiet-vite-rollup-options-alias.md diff --git a/.agents/skills/authentication/SKILL.md b/.agents/skills/authentication/SKILL.md index e3eb08fea3..959615461a 100644 --- a/.agents/skills/authentication/SKILL.md +++ b/.agents/skills/authentication/SKILL.md @@ -23,6 +23,7 @@ Auth is powered by **Better Auth** with account-first design. Every new user cre | **Production (default)** | Magic-link-first Better Auth when outbound email is ready, with email/password fallback and social providers (Google, GitHub). Organizations built in. | | **`AUTH_MODE=local`** | **Not** a browser auth bypass, and never returns `local@localhost`. It only affects CLI/agent identity: it lets `pnpm action` / the local agent loop auto-bind to the single real signed-in dev user from the `sessions` table (see `scripts/dev-session.ts`). Browser login is unchanged. | | **`AUTH_SKIP_EMAIL_VERIFICATION=1`** | QA/preview escape hatch for password-fallback accounts. Signup skips email verification and does not send the signup verification email. Local dev/test skips verification by default; set `AUTH_SKIP_EMAIL_VERIFICATION=0` only when testing verification itself. It does not change magic-link delivery. Use `+qa` emails for test accounts. | +| **`auth.requireEmailVerification`** | Declares the password-signup verification policy for any environment, production included, via `defineAppConfig({ auth: { requireEmailVerification: false } })` or `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. A declared value outranks `AUTH_SKIP_EMAIL_VERIFICATION` and the per-environment default. `false` accepts an unverified address as a login credential; `true` with no email provider disables password signup instead of stranding accounts on a verification nobody can deliver. | | **`AUTH_MAGIC_LINK=0`** | Force the email/password fallback even when outbound email is ready. | | **`AUTH_DISABLED=true`** | Skip login/signup entirely — every request runs as `dev@local.test`. For local dev, cloud previews, and internal demos only; not for production with real users. | | **`ACCESS_TOKEN` / `ACCESS_TOKENS`** | Static bearer fallback for MCP/connect clients that cannot use OAuth. Not browser auth and never a token login page. | diff --git a/.changeset/auth-require-email-verification-config.md b/.changeset/auth-require-email-verification-config.md new file mode 100644 index 0000000000..15707f6cc0 --- /dev/null +++ b/.changeset/auth-require-email-verification-config.md @@ -0,0 +1,13 @@ +--- +"@agent-native/core": minor +--- + +Add `auth.requireEmailVerification` to the app config schema, aliased to +`AUTH_REQUIRE_EMAIL_VERIFICATION`, so a deployment can state its password-signup +verification policy instead of inheriting the environment-derived one. +`AUTH_SKIP_EMAIL_VERIFICATION` stays a local/QA-only convenience that hosted +deployments ignore; a declared value outranks it. Setting the field to `false` +accepts an unverified address as a login credential and therefore also lifts the +hosted no-email-provider signup lock, which exists to prevent exactly that; +setting it to `true` where no email provider is configured disables password +signup rather than stranding accounts on a verification that cannot be delivered. diff --git a/.changeset/quiet-vite-rollup-options-alias.md b/.changeset/quiet-vite-rollup-options-alias.md new file mode 100644 index 0000000000..4740a1b3a2 --- /dev/null +++ b/.changeset/quiet-vite-rollup-options-alias.md @@ -0,0 +1,5 @@ +--- +"@agent-native/core": patch +--- + +Stop the dev server from warning that the `agent-native-config` plugin set both `rollupOptions` and `rolldownOptions`. Vite 8 exposes `rollupOptions` as a getter alias of `rolldownOptions`, and spreading the incoming `build` / `optimizeDeps` sections copied that alias back out alongside our own `rolldownOptions`. diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 6073aa4578..6212ecc573 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -351,37 +351,38 @@ wins over any of them. These fields are deliberately separate from the public `agent-native.config.ts` surface. Fields with no alias are settable only in code. -| Field | Environment aliases | Type | Default | Description | -| --------------------------------------------- | --------------------------------------------------------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `a2a.allowedOrigins` | `AGENT_NATIVE_A2A_ALLOWED_ORIGINS` | array | `[]` | Comma-separated extra origins trusted as private A2A siblings. | -| `a2a.allowUnsignedInternal` | `A2A_ALLOW_UNSIGNED_INTERNAL` | boolean | `false` | Trust unsigned internal self-dispatch on an unrecognized non-production host. Never grants trust in production. | -| `agent.engine` | `AGENT_ENGINE` | string | — | Name of the registered agent engine to use. | -| `agent.model` | `AGENT_MODEL` | string | — | Model the agent runs with, when the caller does not pass one. | -| `agent.mode` | `AGENT_MODE` | string | — | Runtime mode. "production" turns off development-only agent behavior. | -| `agent.preferBringYourOwnKey` | `AGENT_ENGINE_PREFER_BYO_KEY` | boolean | `false` | Skip the Builder-managed engine and select a directly configured provider key first. | -| `agent.runSoftTimeoutMs` | `AGENT_RUN_SOFT_TIMEOUT_MS` | number | — | Soft timeout for an agent run, in milliseconds. 0 disables it. | -| `agent.completedRunRetentionMs` | `AGENT_RUN_RETENTION_MS` | number | — | How long a completed agent run row is kept, in milliseconds. | -| `agent.erroredRunRetentionMs` | `AGENT_ERRORED_RUN_RETENTION_MS` | number | — | How long an errored agent run row is kept, in milliseconds. | -| `agent.backgroundNoProgressTimeoutMs` | `AGENT_BACKGROUND_NO_PROGRESS_TIMEOUT_MS` | number | `150000` | No-progress backstop for a background-function run, in milliseconds. 0 disables it. | -| `agent.backgroundRunHardTimeoutMs` | `AGENT_BACKGROUND_RUN_HARD_TIMEOUT_MS` | number | `600000` | Hard abort for one in-process background automation run, in milliseconds. This is the host's real function budget for scheduled work. | -| `app.id` | `AGENT_NATIVE_APP_ID`, `APP_ID` | string | — | Stable identity of this app deployment. | -| `app.workspaceId` | `AGENT_NATIVE_WORKSPACE_APP_ID`, `VITE_AGENT_NATIVE_WORKSPACE_APP_ID` | string | — | Identity assigned by a workspace deploy. Credential grants are scoped to this. | -| `app.name` | `APP_NAME` | string | — | User-facing display name of this app. | -| `app.pingMessage` | `PING_MESSAGE` | string | `"pong"` | Message returned by the framework ping route. | -| `app.healthStrictSchema` | `AGENT_NATIVE_HEALTH_STRICT_SCHEMA` | boolean | `false` | Return HTTP 503 when the framework health schema probe is not ready. | -| `app.url` | `APP_URL`, `VITE_APP_URL`, `BETTER_AUTH_URL`, `VITE_BETTER_AUTH_URL` | string | — | Canonical public URL of this app, used for user-facing links. | -| `app.packageName` | `npm_package_name` | string | — | Package name of the running app, as npm sets it for a script. | -| `app.template` | `VITE_AGENT_NATIVE_TEMPLATE` | string | — | First-party template this app was generated from. | -| `auth.disableDesktopSsoFallbackInDevelopment` | `AGENT_NATIVE_DISABLE_DESKTOP_SSO_FALLBACK` | boolean | `false` | Disable the loopback Desktop SSO fallback in development so isolated acceptance runs can use their configured local identity. Ignored in production. | -| `integrations.allowUnverifiedWebhooks` | `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS` | boolean | `false` | Skip inbound webhook signature verification. Development only — every adapter that reads this treats it as a bypass of sender authentication. | -| `migration.releaseMigrations` | `AGENT_NATIVE_RELEASE_MIGRATIONS` | boolean | `false` | Treat database migrations as release-owned so request runtimes only probe an already-prepared schema. | -| `migration.betaSchemaOwner` | `AGENT_NATIVE_BETA_SCHEMA_OWNER` | string | — | Schema owner marker embedded in a prebuilt beta server bundle. | -| `privateBlob.provider` | — | string | — | Id of the registered private blob provider to use. Unset falls back to the first registered provider that reports itself configured. | -| `privateBlob.publicUploadFallback` | `AGENT_NATIVE_PRIVATE_BLOB_PUBLIC_UPLOAD_FALLBACK` | boolean | `true` | Store private blobs as encrypted objects in public file-upload storage when no private blob provider is configured. | -| `workspace.isWorkspace` | `AGENT_NATIVE_WORKSPACE`, `VITE_AGENT_NATIVE_WORKSPACE` | boolean | — | Whether this app is mounted inside a shared workspace gateway. | -| `workspace.appsJson` | `AGENT_NATIVE_WORKSPACE_APPS_JSON`, `VITE_AGENT_NATIVE_WORKSPACE_APPS_JSON` | string | — | Serialized workspace app manifest used by mounted app runtimes. | -| `workspace.gatewayUrl` | `WORKSPACE_GATEWAY_URL`, `VITE_WORKSPACE_GATEWAY_URL` | string | — | URL of the workspace gateway fronting this app. | -| `workspace.orgDirectoryUrl` | `AGENT_NATIVE_ORG_DIRECTORY_URL` | string | — | URL of the authoritative organization Dispatch directory. | -| `workspace.oauthOrigin` | `WORKSPACE_OAUTH_ORIGIN`, `VITE_WORKSPACE_OAUTH_ORIGIN` | string | — | Shared origin workspace apps complete OAuth against. | +| Field | Environment aliases | Type | Default | Description | +| --------------------------------------------- | --------------------------------------------------------------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `a2a.allowedOrigins` | `AGENT_NATIVE_A2A_ALLOWED_ORIGINS` | array | `[]` | Comma-separated extra origins trusted as private A2A siblings. | +| `a2a.allowUnsignedInternal` | `A2A_ALLOW_UNSIGNED_INTERNAL` | boolean | `false` | Trust unsigned internal self-dispatch on an unrecognized non-production host. Never grants trust in production. | +| `agent.engine` | `AGENT_ENGINE` | string | — | Name of the registered agent engine to use. | +| `agent.model` | `AGENT_MODEL` | string | — | Model the agent runs with, when the caller does not pass one. | +| `agent.mode` | `AGENT_MODE` | string | — | Runtime mode. "production" turns off development-only agent behavior. | +| `agent.preferBringYourOwnKey` | `AGENT_ENGINE_PREFER_BYO_KEY` | boolean | `false` | Skip the Builder-managed engine and select a directly configured provider key first. | +| `agent.runSoftTimeoutMs` | `AGENT_RUN_SOFT_TIMEOUT_MS` | number | — | Soft timeout for an agent run, in milliseconds. 0 disables it. | +| `agent.completedRunRetentionMs` | `AGENT_RUN_RETENTION_MS` | number | — | How long a completed agent run row is kept, in milliseconds. | +| `agent.erroredRunRetentionMs` | `AGENT_ERRORED_RUN_RETENTION_MS` | number | — | How long an errored agent run row is kept, in milliseconds. | +| `agent.backgroundNoProgressTimeoutMs` | `AGENT_BACKGROUND_NO_PROGRESS_TIMEOUT_MS` | number | `150000` | No-progress backstop for a background-function run, in milliseconds. 0 disables it. | +| `agent.backgroundRunHardTimeoutMs` | `AGENT_BACKGROUND_RUN_HARD_TIMEOUT_MS` | number | `600000` | Hard abort for one in-process background automation run, in milliseconds. This is the host's real function budget for scheduled work. | +| `app.id` | `AGENT_NATIVE_APP_ID`, `APP_ID` | string | — | Stable identity of this app deployment. | +| `app.workspaceId` | `AGENT_NATIVE_WORKSPACE_APP_ID`, `VITE_AGENT_NATIVE_WORKSPACE_APP_ID` | string | — | Identity assigned by a workspace deploy. Credential grants are scoped to this. | +| `app.name` | `APP_NAME` | string | — | User-facing display name of this app. | +| `app.pingMessage` | `PING_MESSAGE` | string | `"pong"` | Message returned by the framework ping route. | +| `app.healthStrictSchema` | `AGENT_NATIVE_HEALTH_STRICT_SCHEMA` | boolean | `false` | Return HTTP 503 when the framework health schema probe is not ready. | +| `app.url` | `APP_URL`, `VITE_APP_URL`, `BETTER_AUTH_URL`, `VITE_BETTER_AUTH_URL` | string | — | Canonical public URL of this app, used for user-facing links. | +| `app.packageName` | `npm_package_name` | string | — | Package name of the running app, as npm sets it for a script. | +| `app.template` | `VITE_AGENT_NATIVE_TEMPLATE` | string | — | First-party template this app was generated from. | +| `auth.disableDesktopSsoFallbackInDevelopment` | `AGENT_NATIVE_DISABLE_DESKTOP_SSO_FALLBACK` | boolean | `false` | Disable the loopback Desktop SSO fallback in development so isolated acceptance runs can use their configured local identity. Ignored in production. | +| `auth.requireEmailVerification` | `AUTH_REQUIRE_EMAIL_VERIFICATION` | boolean | — | Whether password signup must verify the email address before it gets a session. Unset derives it: hosted deployments require it, local development skips it. Setting it false accepts an unverified email as a login credential, including in production. | +| `integrations.allowUnverifiedWebhooks` | `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS` | boolean | `false` | Skip inbound webhook signature verification. Development only — every adapter that reads this treats it as a bypass of sender authentication. | +| `migration.releaseMigrations` | `AGENT_NATIVE_RELEASE_MIGRATIONS` | boolean | `false` | Treat database migrations as release-owned so request runtimes only probe an already-prepared schema. | +| `migration.betaSchemaOwner` | `AGENT_NATIVE_BETA_SCHEMA_OWNER` | string | — | Schema owner marker embedded in a prebuilt beta server bundle. | +| `privateBlob.provider` | — | string | — | Id of the registered private blob provider to use. Unset falls back to the first registered provider that reports itself configured. | +| `privateBlob.publicUploadFallback` | `AGENT_NATIVE_PRIVATE_BLOB_PUBLIC_UPLOAD_FALLBACK` | boolean | `true` | Store private blobs as encrypted objects in public file-upload storage when no private blob provider is configured. | +| `workspace.isWorkspace` | `AGENT_NATIVE_WORKSPACE`, `VITE_AGENT_NATIVE_WORKSPACE` | boolean | — | Whether this app is mounted inside a shared workspace gateway. | +| `workspace.appsJson` | `AGENT_NATIVE_WORKSPACE_APPS_JSON`, `VITE_AGENT_NATIVE_WORKSPACE_APPS_JSON` | string | — | Serialized workspace app manifest used by mounted app runtimes. | +| `workspace.gatewayUrl` | `WORKSPACE_GATEWAY_URL`, `VITE_WORKSPACE_GATEWAY_URL` | string | — | URL of the workspace gateway fronting this app. | +| `workspace.orgDirectoryUrl` | `AGENT_NATIVE_ORG_DIRECTORY_URL` | string | — | URL of the authoritative organization Dispatch directory. | +| `workspace.oauthOrigin` | `WORKSPACE_OAUTH_ORIGIN`, `VITE_WORKSPACE_OAUTH_ORIGIN` | string | — | Shared origin workspace apps complete OAuth against. | diff --git a/packages/core/docs/content/authentication.mdx b/packages/core/docs/content/authentication.mdx index 5c110d165c..03ed2b791c 100644 --- a/packages/core/docs/content/authentication.mdx +++ b/packages/core/docs/content/authentication.mdx @@ -210,6 +210,24 @@ verification and the signup verification email is not sent. It does not change magic-link delivery. Use it only for QA or preview environments, and name test accounts with a `+qa` address (`name+qa@example.com`) so they are easy to identify. +## Email Verification Policy {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` is a local and QA convenience — a hosted +deployment ignores it. To state the policy for any environment, production +included, declare it in config: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +The deployment alias is `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. A declared value +outranks both `AUTH_SKIP_EMAIL_VERIFICATION` and the per-environment default. + +`false` accepts an unverified address as a login credential — anyone can claim +any email — so use it only where signup is already restricted another way. +`true` on a deployment with no email provider disables password signup instead, +because the verification could never be delivered. + ## Social Providers {#social-providers} Set environment variables to enable social login. Better Auth auto-detects them: @@ -477,27 +495,28 @@ The default `/_agent-native/google/auth-url` route does this automatically — o ## Environment Variables {#environment-variables} -| Variable | Purpose | -| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| `BETTER_AUTH_SECRET` | Signing key for Better Auth (auto-generated if not set) | -| `AUTH_SKIP_EMAIL_VERIFICATION` | Set to `1` in QA/preview environments to let password-fallback signups proceed without verification; local dev/test skips by default | -| `AUTH_MAGIC_LINK` | Set to `0`, `false`, or `off` to force the email/password fallback even when outbound email is ready | -| `AUTH_DISABLED` | Set to `true` or `1` to skip login/signup; all requests run as one shared user (local dev/preview only — not for production with real users) | -| `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Set to `1` to disable localhost auto-sign-in on a fresh dev database | -| `AUTH_MODE` | `local` resolves CLI/agent identity only (which dev user `pnpm action` runs as); never a browser login bypass | -| `COOKIE_DOMAIN` | Opt into shared session cookies across same-database subdomains (see [Cookie Realms](#cookie-realms)) | -| `AGENT_NATIVE_WORKSPACE` | `1` runs in workspace mode — one shared session realm across workspace apps | -| `AGENT_NATIVE_SHARE_COOKIE_DOMAIN` | Set with `COOKIE_DOMAIN` to share one auth database across first-party subdomains | -| `OAUTH_STATE_SECRET` | Dedicated HMAC key for OAuth state envelopes (see [Security — OAuth State Signing](/docs/security#oauth-state)) | -| `GOOGLE_SIGN_IN_CLIENT_ID` | Preferred low-scope Google OAuth client ID for app login | -| `GOOGLE_SIGN_IN_CLIENT_SECRET` | Preferred low-scope Google OAuth secret for app login | -| `GOOGLE_CLIENT_ID` | Legacy Google login fallback, and provider OAuth client ID for Google API integrations | -| `GOOGLE_CLIENT_SECRET` | Legacy Google login fallback, and provider OAuth secret for Google API integrations | -| `GITHUB_CLIENT_ID` | Enable GitHub OAuth | -| `GITHUB_CLIENT_SECRET` | GitHub OAuth secret | -| `ACCESS_TOKEN` | Static bearer fallback for MCP/connect clients; not browser auth | -| `ACCESS_TOKENS` | Comma-separated static bearer fallbacks for MCP/connect clients; not browser auth | -| `A2A_SECRET` | Shared secret for JWT-signed A2A cross-app identity verification and, when present, MCP OAuth access-token signing | +| Variable | Purpose | +| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `BETTER_AUTH_SECRET` | Signing key for Better Auth (auto-generated if not set) | +| `AUTH_SKIP_EMAIL_VERIFICATION` | Set to `1` in QA/preview environments to let password-fallback signups proceed without verification; local dev/test skips by default | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | Set to `0` or `1` to declare the password-signup verification policy for any environment, production included; outranks `AUTH_SKIP_EMAIL_VERIFICATION` | +| `AUTH_MAGIC_LINK` | Set to `0`, `false`, or `off` to force the email/password fallback even when outbound email is ready | +| `AUTH_DISABLED` | Set to `true` or `1` to skip login/signup; all requests run as one shared user (local dev/preview only — not for production with real users) | +| `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Set to `1` to disable localhost auto-sign-in on a fresh dev database | +| `AUTH_MODE` | `local` resolves CLI/agent identity only (which dev user `pnpm action` runs as); never a browser login bypass | +| `COOKIE_DOMAIN` | Opt into shared session cookies across same-database subdomains (see [Cookie Realms](#cookie-realms)) | +| `AGENT_NATIVE_WORKSPACE` | `1` runs in workspace mode — one shared session realm across workspace apps | +| `AGENT_NATIVE_SHARE_COOKIE_DOMAIN` | Set with `COOKIE_DOMAIN` to share one auth database across first-party subdomains | +| `OAUTH_STATE_SECRET` | Dedicated HMAC key for OAuth state envelopes (see [Security — OAuth State Signing](/docs/security#oauth-state)) | +| `GOOGLE_SIGN_IN_CLIENT_ID` | Preferred low-scope Google OAuth client ID for app login | +| `GOOGLE_SIGN_IN_CLIENT_SECRET` | Preferred low-scope Google OAuth secret for app login | +| `GOOGLE_CLIENT_ID` | Legacy Google login fallback, and provider OAuth client ID for Google API integrations | +| `GOOGLE_CLIENT_SECRET` | Legacy Google login fallback, and provider OAuth secret for Google API integrations | +| `GITHUB_CLIENT_ID` | Enable GitHub OAuth | +| `GITHUB_CLIENT_SECRET` | GitHub OAuth secret | +| `ACCESS_TOKEN` | Static bearer fallback for MCP/connect clients; not browser auth | +| `ACCESS_TOKENS` | Comma-separated static bearer fallbacks for MCP/connect clients; not browser auth | +| `A2A_SECRET` | Shared secret for JWT-signed A2A cross-app identity verification and, when present, MCP OAuth access-token signing | ## What's next diff --git a/packages/core/docs/content/environment-variables.mdx b/packages/core/docs/content/environment-variables.mdx index 2106ec599e..3ad5259c7b 100644 --- a/packages/core/docs/content/environment-variables.mdx +++ b/packages/core/docs/content/environment-variables.mdx @@ -87,6 +87,7 @@ public app behavior, use the config paths above instead. | `AUTH_DISABLED` | Disables auth for local or preview-only work. Unset already means false. | `true` or `1`; never use on a public production app. | | `AUTH_MAGIC_LINK` | Controls the password-first versus magic-link sign-in path. | `0` keeps password-first sign-in; otherwise a configured email transport can enable magic links. | | `AUTH_SKIP_EMAIL_VERIFICATION` | Skips signup email verification for local QA or previews. | `1`; never use it to weaken production auth. | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | Declares whether password signup must verify the email address, in any environment. | `0` or `1`; outranks `AUTH_SKIP_EMAIL_VERIFICATION`. `0` accepts an unverified address as a login credential. | | `ACCESS_TOKEN` / `ACCESS_TOKENS` | Static bearer fallback for MCP and Connect clients. | One token or a delimited token list; these are not browser auth. | | `AGENT_PROD_CODE_EXECUTION` | Production code-execution policy. | `off`, `sandboxed`, or `trusted`. See [Production Code Execution](/docs/actions-agent-tools#production-code-execution). | | `AGENT_NATIVE_SSR_CACHE` | Deployment-wide public SSR shell cache policy. | Unset/`on`, `off`, or a duration such as `30s` or `5m`. See [SSR Caching](/docs/ssr-caching). | diff --git a/packages/core/docs/content/locales/ar-SA/authentication.mdx b/packages/core/docs/content/locales/ar-SA/authentication.mdx index 38f6b49493..fd2468d611 100644 --- a/packages/core/docs/content/locales/ar-SA/authentication.mdx +++ b/packages/core/docs/content/locales/ar-SA/authentication.mdx @@ -166,6 +166,24 @@ AUTH_SKIP_EMAIL_VERIFICATION=1 أو معاينة البيئات، وتسمية حسابات الاختبار بعنوان `+qa` (`name+qa@example.com`) حتى يسهل التعرف عليها. +## سياسة التحقق من البريد الإلكتروني {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` هو وسيلة راحة محلية ولضمان الجودة — وتتجاهله أي +عملية نشر مُستضافة. لتحديد السياسة لأي بيئة، بما في ذلك الإنتاج، صرِّح بها في +الإعدادات: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +الاسم المستعار للنشر هو `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. القيمة المُصرَّح بها +تتفوق على `AUTH_SKIP_EMAIL_VERIFICATION` وعلى الافتراضي الخاص بكل بيئة معًا. + +تقبل القيمة `false` عنوانًا غير مُتحقق منه كبيانات اعتماد لتسجيل الدخول — إذ +يمكن لأي شخص المطالبة بأي بريد إلكتروني — لذا استخدمها فقط حيث يكون الاشتراك +مقيدًا بالفعل بطريقة أخرى. أما `true` في عملية نشر بلا مزوّد بريد إلكتروني فتعطل +الاشتراك بكلمة مرور بدلًا من ذلك، لأن رسالة التحقق لن يمكن تسليمها أبدًا. + ## مقدمو الخدمات الاجتماعية {#social-providers} قم بتعيين متغيرات البيئة لتمكين تسجيل الدخول الاجتماعي. تكتشفها المصادقة الأفضل تلقائيًا: @@ -436,6 +454,7 @@ const state = encodeOAuthState({ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `BETTER_AUTH_SECRET` | مفتاح التوقيع لمصادقة أفضل (يتم إنشاؤه تلقائيًا إذا لم يتم تعيينه) | | `AUTH_SKIP_EMAIL_VERIFICATION` | قم بالتعيين على `1` في بيئات ضمان الجودة/المعاينة للسماح بمتابعة عمليات الاشتراك في البريد الإلكتروني/كلمة المرور دون التحقق؛ يتم تخطي التطوير/الاختبار المحلي افتراضيًا | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | عيِّنه على `0` أو `1` لتحديد سياسة التحقق لاشتراكات كلمة المرور في أي بيئة، بما في ذلك الإنتاج؛ يتفوق على `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | اضبط على `true` أو `1` لتخطي تسجيل الدخول/الاشتراك؛ يتم تشغيل جميع الطلبات كمستخدم واحد مشترك (للتطوير/المعاينة المحلية فقط - وليس للإنتاج مع مستخدمين حقيقيين) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | اضبط على `1` لتعطيل تسجيل الدخول التلقائي للمضيف المحلي في قاعدة بيانات جديدة للمطورين | | `AUTH_MODE` | يحل `local` هوية CLI/الوكيل فقط (الذي يعمل عليه مستخدم التطوير `pnpm action`)؛ لا تقم أبدًا بتجاوز تسجيل الدخول إلى المتصفح | diff --git a/packages/core/docs/content/locales/de-DE/authentication.mdx b/packages/core/docs/content/locales/de-DE/authentication.mdx index 5fb2ab16a4..8641bcbfb2 100644 --- a/packages/core/docs/content/locales/de-DE/authentication.mdx +++ b/packages/core/docs/content/locales/de-DE/authentication.mdx @@ -166,6 +166,27 @@ Bestätigung und die Anmeldebestätigungs-E-Mail wird nicht gesendet. Verwenden oder Vorschauumgebungen und benennen Sie Testkonten mit einer `+qa`-Adresse (`name+qa@example.com`), damit sie leicht zu identifizieren sind. +## Richtlinie zur E-Mail-Überprüfung {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` ist eine lokale und QA-Bequemlichkeit — eine +gehostete Bereitstellung ignoriert sie. Um die Richtlinie für jede Umgebung +festzulegen, einschließlich der Produktion, deklarieren Sie sie in der +Konfiguration: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +Der Bereitstellungsalias lautet `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. Ein +deklarierter Wert übertrifft sowohl `AUTH_SKIP_EMAIL_VERIFICATION` als auch die +Standardeinstellung der jeweiligen Umgebung. + +`false` akzeptiert eine nicht überprüfte Adresse als Anmeldeinformation — jeder +kann jede E-Mail-Adresse beanspruchen — verwenden Sie es also nur dort, wo die +Anmeldung bereits anderweitig eingeschränkt ist. `true` deaktiviert auf einer +Bereitstellung ohne E-Mail-Anbieter stattdessen die Passwortanmeldung, da die +Überprüfung nie zugestellt werden könnte. + ## Soziale Anbieter {#social-providers} Legen Sie Umgebungsvariablen fest, um die soziale Anmeldung zu ermöglichen. Better Auth erkennt sie automatisch: @@ -438,6 +459,7 @@ Die Standardroute `/_agent-native/google/auth-url` führt dies automatisch aus | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | Signaturschlüssel für Better Auth (automatisch generiert, wenn nicht festgelegt) | | `AUTH_SKIP_EMAIL_VERIFICATION` | In QA-/Vorschauumgebungen auf `1` setzen, damit E-Mail-/Passwort-Anmeldungen ohne Überprüfung durchgeführt werden können. Lokale Entwicklung/Test überspringt standardmäßig | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | Auf `0` oder `1` setzen, um die Überprüfungsrichtlinie für die Passwortanmeldung in jeder Umgebung festzulegen, einschließlich der Produktion; übertrifft `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | Auf `true` oder `1` einstellen, um Anmeldung/Registrierung zu überspringen; Alle Anfragen werden von einem gemeinsamen Benutzer ausgeführt (nur lokale Entwicklung/Vorschau – nicht für die Produktion mit echten Benutzern) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Auf `1` einstellen, um die automatische Anmeldung von Localhost in einer neuen Entwicklungsdatenbank zu deaktivieren | | `AUTH_MODE` | `local` löst nur die CLI/Agent-Identität auf (unter der der Entwicklerbenutzer `pnpm action` ausgeführt wird); niemals eine Browser-Anmeldeumgehung | diff --git a/packages/core/docs/content/locales/es-ES/authentication.mdx b/packages/core/docs/content/locales/es-ES/authentication.mdx index e061eba06c..614a502bc2 100644 --- a/packages/core/docs/content/locales/es-ES/authentication.mdx +++ b/packages/core/docs/content/locales/es-ES/authentication.mdx @@ -166,6 +166,26 @@ no se envía la verificación y el correo electrónico de verificación de regis o obtener una vista previa de los entornos y nombrar cuentas de prueba con una dirección `+qa` (`name+qa@example.com`) para que sean fáciles de identificar. +## Política de verificación de correo electrónico {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` es una comodidad local y de control de calidad: +una implementación alojada la ignora. Para declarar la política en cualquier +entorno, incluida la producción, decláresela en la configuración: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +El alias de implementación es `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. Un valor +declarado prevalece tanto sobre `AUTH_SKIP_EMAIL_VERIFICATION` como sobre el +valor predeterminado de cada entorno. + +`false` acepta una dirección no verificada como credencial de inicio de sesión +—cualquiera puede reclamar cualquier correo electrónico—, así que úselo solo +donde el registro ya esté restringido de otra manera. `true` en una +implementación sin proveedor de correo electrónico deshabilita el registro con +contraseña, porque la verificación nunca podría entregarse. + ## Proveedores sociales {#social-providers} Establezca variables de entorno para habilitar el inicio de sesión social. Better Auth los detecta automáticamente: @@ -438,6 +458,7 @@ La ruta `/_agent-native/google/auth-url` predeterminada hace esto automáticamen | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | Clave de firma para una mejor autenticación (generada automáticamente si no está configurada) | | `AUTH_SKIP_EMAIL_VERIFICATION` | Establezca en `1` en entornos de control de calidad/vista previa para permitir que los registros de correo electrónico/contraseña se realicen sin verificación; El desarrollo/prueba local se salta de forma predeterminada | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | Establezca en `0` o `1` para declarar la política de verificación del registro con contraseña en cualquier entorno, incluida la producción; prevalece sobre `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | Establezca en `true` o `1` para omitir el inicio de sesión/registro; todas las solicitudes se ejecutan como un usuario compartido (solo desarrollo/vista previa local, no para producción con usuarios reales) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Establezca en `1` para deshabilitar el inicio de sesión automático de localhost en una base de datos de desarrollo nueva | | `AUTH_MODE` | `local` resuelve solo la identidad de CLI/agente (con la que se ejecuta el usuario de desarrollo `pnpm action`); nunca una omisión de inicio de sesión del navegador | diff --git a/packages/core/docs/content/locales/fr-FR/authentication.mdx b/packages/core/docs/content/locales/fr-FR/authentication.mdx index 5c52a8ac12..a7cbc3d861 100644 --- a/packages/core/docs/content/locales/fr-FR/authentication.mdx +++ b/packages/core/docs/content/locales/fr-FR/authentication.mdx @@ -166,6 +166,26 @@ vérification et l'e-mail de vérification de l'inscription n'est pas envoyé. U ou prévisualisez les environnements et nommez les comptes de test avec une adresse `+qa` (`name+qa@example.com`) pour qu'ils soient faciles à identifier. +## Politique de vérification des e-mails {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` est une commodité locale et de contrôle qualité : +un déploiement hébergé l'ignore. Pour définir la politique dans n'importe quel +environnement, production comprise, déclarez-la dans la configuration : + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +L'alias de déploiement est `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. Une valeur +déclarée l'emporte à la fois sur `AUTH_SKIP_EMAIL_VERIFICATION` et sur la +valeur par défaut de chaque environnement. + +`false` accepte une adresse non vérifiée comme identifiant de connexion — +n'importe qui peut revendiquer n'importe quel e-mail — ne l'utilisez donc que +là où l'inscription est déjà restreinte autrement. `true` sur un déploiement +sans fournisseur d'e-mail désactive plutôt l'inscription par mot de passe, car +la vérification ne pourrait jamais être délivrée. + ## Prestataires sociaux {#social-providers} Définissez les variables d'environnement pour activer la connexion sociale. Better Auth les détecte automatiquement : @@ -438,6 +458,7 @@ La route `/_agent-native/google/auth-url` par défaut le fait automatiquement : | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | Clé de signature pour une meilleure authentification (générée automatiquement si elle n'est pas définie) | | `AUTH_SKIP_EMAIL_VERIFICATION` | Défini sur `1` dans les environnements QA/preview pour permettre aux inscriptions par e-mail/mot de passe de se dérouler sans vérification ; le développement/test local est ignoré par défaut | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | Défini sur `0` ou `1` pour déclarer la politique de vérification de l'inscription par mot de passe dans n'importe quel environnement, production comprise ; l'emporte sur `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | Définissez sur `true` ou `1` pour ignorer la connexion/l'inscription ; toutes les requêtes s'exécutent en tant qu'utilisateur partagé (développement/aperçu local uniquement – pas pour la production avec de vrais utilisateurs) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Définissez sur `1` pour désactiver la connexion automatique de localhost sur une nouvelle base de données de développement | | `AUTH_MODE` | `local` résout uniquement l'identité de CLI/agent (sous quel utilisateur de développement `pnpm action` s'exécute) ; jamais de contournement de connexion au navigateur | diff --git a/packages/core/docs/content/locales/hi-IN/authentication.mdx b/packages/core/docs/content/locales/hi-IN/authentication.mdx index 1c2dbe9f1d..fce9d497d5 100644 --- a/packages/core/docs/content/locales/hi-IN/authentication.mdx +++ b/packages/core/docs/content/locales/hi-IN/authentication.mdx @@ -166,6 +166,25 @@ AUTH_SKIP_EMAIL_VERIFICATION=1 या परिवेश का पूर्वावलोकन करें, और `+qa` पते के साथ परीक्षण खातों को नाम दें (`name+qa@example.com`) ताकि उन्हें पहचानना आसान हो। +## ईमेल सत्यापन नीति {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` एक स्थानीय और QA सुविधा है — होस्ट की गई तैनाती +इसे अनदेखा करती है। उत्पादन सहित किसी भी वातावरण के लिए नीति बताने हेतु, इसे +कॉन्फ़िगरेशन में घोषित करें: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +तैनाती उपनाम `AUTH_REQUIRE_EMAIL_VERIFICATION=0` है। घोषित मान +`AUTH_SKIP_EMAIL_VERIFICATION` और प्रति-वातावरण डिफ़ॉल्ट, दोनों से ऊपर रहता है। + +`false` एक असत्यापित पते को लॉगिन क्रेडेंशियल के रूप में स्वीकार करता है — कोई भी +किसी भी ईमेल का दावा कर सकता है — इसलिए इसका उपयोग केवल वहीं करें जहाँ साइनअप +पहले से किसी अन्य तरीके से सीमित हो। बिना ईमेल प्रदाता वाली तैनाती पर `true` +इसके बजाय पासवर्ड साइनअप को अक्षम कर देता है, क्योंकि सत्यापन कभी वितरित नहीं +हो सकता। + ## सामाजिक प्रदाता {#social-providers} सामाजिक लॉगिन सक्षम करने के लिए पर्यावरण चर सेट करें। Better Auth उनका स्वत: पता लगाता है: @@ -438,6 +457,7 @@ const state = encodeOAuthState({ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | बेहतर प्रमाणीकरण के लिए हस्ताक्षर कुंजी (यदि सेट नहीं है तो स्वतः उत्पन्न) | | `AUTH_SKIP_EMAIL_VERIFICATION` | ईमेल/पासवर्ड साइनअप को सत्यापन के बिना आगे बढ़ने देने के लिए QA/पूर्वावलोकन वातावरण में `1` पर सेट करें; स्थानीय विकास/परीक्षण डिफ़ॉल्ट रूप से स्किप हो जाता है | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | उत्पादन सहित किसी भी वातावरण के लिए पासवर्ड साइनअप की सत्यापन नीति घोषित करने हेतु `0` या `1` सेट करें; यह `AUTH_SKIP_EMAIL_VERIFICATION` से ऊपर रहता है | | `AUTH_DISABLED` | लॉगिन/साइनअप छोड़ने के लिए `true` या `1` पर सेट करें; सभी अनुरोध एक साझा उपयोगकर्ता के रूप में चलते हैं (केवल स्थानीय विकास/पूर्वावलोकन - वास्तविक उपयोगकर्ताओं के साथ उत्पादन के लिए नहीं) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | ताज़ा डेव डेटाबेस पर लोकलहोस्ट ऑटो-साइन-इन को अक्षम करने के लिए `1` पर सेट करें | | `AUTH_MODE` | `local` केवल CLI/एजेंट पहचान का समाधान करता है (जो देव उपयोगकर्ता `pnpm action` के रूप में चलता है); ब्राउज़र लॉगिन को कभी भी बायपास न करें | diff --git a/packages/core/docs/content/locales/ja-JP/authentication.mdx b/packages/core/docs/content/locales/ja-JP/authentication.mdx index f1bcea879f..323d117ab6 100644 --- a/packages/core/docs/content/locales/ja-JP/authentication.mdx +++ b/packages/core/docs/content/locales/ja-JP/authentication.mdx @@ -166,6 +166,24 @@ AUTH_SKIP_EMAIL_VERIFICATION=1 またはプレビュー環境で、`+qa` アドレスを持つテスト アカウントに名前を付けます (`name+qa@example.com`) なので、簡単に識別できます。 +## メール検証ポリシー {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` はローカルおよび QA 向けの利便性であり、ホスト +された環境では無視されます。本番環境を含むあらゆる環境でポリシーを明示するには、 +設定で宣言します: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +デプロイ用のエイリアスは `AUTH_REQUIRE_EMAIL_VERIFICATION=0` です。宣言された値 +は `AUTH_SKIP_EMAIL_VERIFICATION` と環境ごとの既定値の両方より優先されます。 + +`false` は未検証のアドレスをログイン資格情報として受け入れます。誰でも任意のメール +アドレスを主張できるため、サインアップが別の方法ですでに制限されている場合にのみ +使用してください。メールプロバイダーのないデプロイで `true` を設定した場合は、検証 +を配信できないため、代わりにパスワードによるサインアップが無効になります。 + ## ソーシャル プロバイダー {#social-providers} ソーシャル ログインを有効にするために環境変数を設定します。 Better Auth はそれらを自動検出します: @@ -438,6 +456,7 @@ const state = encodeOAuthState({ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `BETTER_AUTH_SECRET` | Better Auth 用の署名キー (設定されていない場合は自動生成されます) | | `AUTH_SKIP_EMAIL_VERIFICATION` | QA/プレビュー環境で `1` に設定すると、電子メール/パスワードのサインアップが検証なしで続行できるようになります。ローカルの開発/テストはデフォルトでスキップされます | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | `0` または `1` を設定すると、本番環境を含むあらゆる環境でパスワードサインアップの検証ポリシーを宣言できます。`AUTH_SKIP_EMAIL_VERIFICATION` より優先されます | | `AUTH_DISABLED` | ログイン/サインアップをスキップするには、`true` または `1` に設定します。すべてのリクエストは 1 人の共有ユーザーとして実行されます (ローカルの開発/プレビューのみ。実際のユーザーによる本番環境では使用できません) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | 新しい開発データベースでローカルホストの自動サインインを無効にするには、`1` に設定します | | `AUTH_MODE` | `local` は、CLI/エージェント ID のみを解決します (開発ユーザー `pnpm action` が実行される)。ブラウザのログインをバイパスしない | diff --git a/packages/core/docs/content/locales/ko-KR/authentication.mdx b/packages/core/docs/content/locales/ko-KR/authentication.mdx index 11d9111613..ad294748b5 100644 --- a/packages/core/docs/content/locales/ko-KR/authentication.mdx +++ b/packages/core/docs/content/locales/ko-KR/authentication.mdx @@ -166,6 +166,24 @@ AUTH_SKIP_EMAIL_VERIFICATION=1 또는 환경을 미리 보고 `+qa` 주소로 테스트 계정 이름을 지정 (`name+qa@example.com`) 쉽게 식별할 수 있습니다. +## 이메일 확인 정책 {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION`은 로컬 및 QA용 편의 기능이며 호스팅된 배포에서는 +무시됩니다. 프로덕션을 포함한 모든 환경에 대해 정책을 명시하려면 구성에서 +선언하세요: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +배포 별칭은 `AUTH_REQUIRE_EMAIL_VERIFICATION=0`입니다. 선언된 값은 +`AUTH_SKIP_EMAIL_VERIFICATION`과 환경별 기본값보다 모두 우선합니다. + +`false`는 확인되지 않은 주소를 로그인 자격 증명으로 허용합니다. 누구나 어떤 +이메일이든 사용할 수 있으므로 가입이 이미 다른 방법으로 제한된 곳에서만 +사용하세요. 이메일 공급자가 없는 배포에서 `true`로 설정하면 확인을 전달할 수 +없으므로 대신 비밀번호 가입이 비활성화됩니다. + ## 소셜 제공자 {#social-providers} 소셜 로그인을 활성화하려면 환경 변수를 설정하세요. Better Auth는 이를 자동으로 감지합니다: @@ -438,6 +456,7 @@ const state = encodeOAuthState({ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | 더 나은 인증을 위한 서명 키(설정되지 않은 경우 자동 생성) | | `AUTH_SKIP_EMAIL_VERIFICATION` | QA/미리보기 환경에서 `1`로 설정하면 확인 없이 이메일/비밀번호 가입이 진행될 수 있습니다. 기본적으로 로컬 개발/테스트 건너뛰기 | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | `0` 또는 `1`로 설정하면 프로덕션을 포함한 모든 환경에서 비밀번호 가입 확인 정책을 선언합니다. `AUTH_SKIP_EMAIL_VERIFICATION`보다 우선합니다 | | `AUTH_DISABLED` | 로그인/가입을 건너뛰려면 `true` 또는 `1`로 설정하세요. 모든 요청은 하나의 공유 사용자로 실행됩니다(로컬 개발/미리 보기에만 해당 - 실제 사용자가 있는 프로덕션에는 해당되지 않음) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | 새로운 개발 데이터베이스에서 로컬 호스트 자동 로그인을 비활성화하려면 `1`로 설정하세요. | | `AUTH_MODE` | `local`는 CLI/에이전트 ID만 확인합니다(개발자 사용자 `pnpm action`가 실행되는 ID). 브라우저 로그인 우회는 절대 안 됩니다 | diff --git a/packages/core/docs/content/locales/pt-BR/authentication.mdx b/packages/core/docs/content/locales/pt-BR/authentication.mdx index 0a9322ecd7..1f6c029651 100644 --- a/packages/core/docs/content/locales/pt-BR/authentication.mdx +++ b/packages/core/docs/content/locales/pt-BR/authentication.mdx @@ -166,6 +166,26 @@ verificação e o e-mail de verificação de inscrição não são enviados. Use ou visualize ambientes e nomeie contas de teste com um endereço `+qa` (`name+qa@example.com`) para que sejam fáceis de identificar. +## Política de verificação de e-mail {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` é uma conveniência local e de controle de +qualidade — uma implantação hospedada a ignora. Para declarar a política em +qualquer ambiente, inclusive produção, declare-a na configuração: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +O alias de implantação é `AUTH_REQUIRE_EMAIL_VERIFICATION=0`. Um valor +declarado prevalece sobre `AUTH_SKIP_EMAIL_VERIFICATION` e sobre o padrão de +cada ambiente. + +`false` aceita um endereço não verificado como credencial de login — qualquer +pessoa pode reivindicar qualquer e-mail —, portanto use-o apenas onde a +inscrição já esteja restrita de outra forma. `true` em uma implantação sem +provedor de e-mail desativa a inscrição por senha, porque a verificação nunca +poderia ser entregue. + ## Provedores Sociais {#social-providers} Defina variáveis de ambiente para ativar o login social. O Better Auth os detecta automaticamente: @@ -438,6 +458,7 @@ A rota `/_agent-native/google/auth-url` padrão faz isso automaticamente – sub | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | Chave de assinatura para Better Auth (gerada automaticamente se não for definida) | | `AUTH_SKIP_EMAIL_VERIFICATION` | Defina como `1` em ambientes de controle de qualidade/visualização para permitir que inscrições de e-mail/senha continuem sem verificação; desenvolvimento/teste local ignora por padrão | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | Defina como `0` ou `1` para declarar a política de verificação da inscrição por senha em qualquer ambiente, inclusive produção; prevalece sobre `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | Defina como `true` ou `1` para ignorar o login/inscrição; todas as solicitações são executadas como um usuário compartilhado (somente desenvolvimento/visualização local — não para produção com usuários reais) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | Defina como `1` para desativar o login automático do host local em um novo banco de dados de desenvolvimento | | `AUTH_MODE` | `local` resolve apenas a identidade CLI/agente (como o usuário desenvolvedor `pnpm action` é executado); nunca um desvio de login do navegador | diff --git a/packages/core/docs/content/locales/zh-CN/authentication.mdx b/packages/core/docs/content/locales/zh-CN/authentication.mdx index 94c39e51a5..17013c264e 100644 --- a/packages/core/docs/content/locales/zh-CN/authentication.mdx +++ b/packages/core/docs/content/locales/zh-CN/authentication.mdx @@ -167,6 +167,22 @@ AUTH_SKIP_EMAIL_VERIFICATION=1 或预览环境,并使用 `+qa` 地址命名测试帐户 (`name+qa@example.com`),因此很容易识别。 +## 电子邮件验证策略 {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` 只是本地和 QA 的便利设置,托管部署会忽略它。要为 +任何环境(包括生产环境)声明该策略,请在配置中声明: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +部署别名为 `AUTH_REQUIRE_EMAIL_VERIFICATION=0`。声明的值优先于 +`AUTH_SKIP_EMAIL_VERIFICATION` 和各环境的默认值。 + +`false` 会将未经验证的地址作为登录凭据接受——任何人都可以声称拥有任何电子邮件 +地址——因此仅在注册已通过其他方式受限时使用。在没有电子邮件提供商的部署上设置 +`true` 则会禁用密码注册,因为验证邮件永远无法送达。 + ## 社交提供商 {#social-providers} 设置环境变量以启用社交登录。 Better Auth 自动检测它们: @@ -439,6 +455,7 @@ const state = encodeOAuthState({ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `BETTER_AUTH_SECRET` | 更好的身份验证签名密钥(如果未设置,则自动生成) | | `AUTH_SKIP_EMAIL_VERIFICATION` | 在 QA/预览环境中设置为 `1`,让电子邮件/密码注册无需验证即可继续进行;默认情况下跳过本地开发/测试 | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | 设置为 `0` 或 `1` 可为任何环境(包括生产环境)声明密码注册的验证策略;优先于 `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | 设置为`true`或`1`跳过登录/注册;所有请求都作为一个共享用户运行(仅限本地开发/预览 - 不适用于真实用户的生产) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | 设置为 `1` 以在新的开发数据库上禁用本地主机自动登录 | | `AUTH_MODE` | `local` 仅解析 CLI/代理身份(开发用户 `pnpm action` 作为其运行);绝不绕过浏览器登录 | diff --git a/packages/core/docs/content/locales/zh-TW/authentication.mdx b/packages/core/docs/content/locales/zh-TW/authentication.mdx index 53c8e09b46..21c3f290f2 100644 --- a/packages/core/docs/content/locales/zh-TW/authentication.mdx +++ b/packages/core/docs/content/locales/zh-TW/authentication.mdx @@ -167,6 +167,22 @@ AUTH_SKIP_EMAIL_VERIFICATION=1 或預覽環境,並使用 `+qa` 地址命名測試帳戶 (`name+qa@example.com`),因此很容易識別。 +## 電子郵件驗證政策 {#email-verification-policy} + +`AUTH_SKIP_EMAIL_VERIFICATION` 只是本機和 QA 的便利設定,託管部署會忽略它。若要 +為任何環境(包括正式環境)宣告該政策,請在設定中宣告: + +```ts +defineAppConfig({ auth: { requireEmailVerification: false } }); +``` + +部署別名為 `AUTH_REQUIRE_EMAIL_VERIFICATION=0`。宣告的值優先於 +`AUTH_SKIP_EMAIL_VERIFICATION` 和各環境的預設值。 + +`false` 會將未經驗證的位址當作登入憑證接受——任何人都可以宣稱擁有任何電子郵件 +位址——因此僅在註冊已透過其他方式受限時使用。在沒有電子郵件供應商的部署上設定 +`true` 則會停用密碼註冊,因為驗證信永遠無法送達。 + ## 社交提供者 {#social-providers} 設定環境變數以啟用社交登入。 Better Auth 自動偵測它們: @@ -439,6 +455,7 @@ const state = encodeOAuthState({ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | `BETTER_AUTH_SECRET` | 更好的驗證簽名金鑰(如果未設定,則自動生成) | | `AUTH_SKIP_EMAIL_VERIFICATION` | 在 QA/預覽環境中設定為 `1`,讓電子郵件/密碼註冊無需驗證即可繼續進行;預設情況下跳過本機開發/測試 | +| `AUTH_REQUIRE_EMAIL_VERIFICATION` | 設定為 `0` 或 `1` 可為任何環境(包括正式環境)宣告密碼註冊的驗證政策;優先於 `AUTH_SKIP_EMAIL_VERIFICATION` | | `AUTH_DISABLED` | 設定為`true`或`1`跳過登入/註冊;所有請求都作為一個共用使用者執行(僅限本機開發/預覽 - 不適用於真實使用者的正式環境) | | `AGENT_NATIVE_DISABLE_AUTO_DEV_ACCOUNT` | 設定為 `1` 以在新的開發資料庫上停用本機主機自動登入 | | `AUTH_MODE` | `local` 僅解析 CLI/代理身分(開發使用者 `pnpm action` 作為其執行);絕不繞過瀏覽器登入 | diff --git a/packages/core/src/app-config/auth.ts b/packages/core/src/app-config/auth.ts index ad930eae58..8e1923a868 100644 --- a/packages/core/src/app-config/auth.ts +++ b/packages/core/src/app-config/auth.ts @@ -5,4 +5,11 @@ export const authConfig = z.object({ env: "AGENT_NATIVE_DISABLE_DESKTOP_SSO_FALLBACK", doc: "Disable the loopback Desktop SSO fallback in development so isolated acceptance runs can use their configured local identity. Ignored in production.", }), + // Deliberately optional rather than defaulted: unset means "derive from the + // deployment", which is not a boolean. A default here would erase the + // difference between an operator who chose a policy and one who never spoke. + requireEmailVerification: z.boolean().optional().meta({ + env: "AUTH_REQUIRE_EMAIL_VERIFICATION", + doc: "Whether password signup must verify the email address before it gets a session. Unset derives it: hosted deployments require it, local development skips it. Setting it false accepts an unverified email as a login credential, including in production.", + }), }); diff --git a/packages/core/src/server/auth.spec.ts b/packages/core/src/server/auth.spec.ts index 69f849a5d2..01d9f2d528 100644 --- a/packages/core/src/server/auth.spec.ts +++ b/packages/core/src/server/auth.spec.ts @@ -140,6 +140,91 @@ describe("server/auth", () => { }, 15_000); }); + describe("auth.requireEmailVerification", () => { + afterEach(async () => { + const { resetAppConfigForTests } = await import("../app-config/index.js"); + resetAppConfigForTests(); + }); + + it("turns verification off in hosted production when declared false", async () => { + vi.stubEnv("NODE_ENV", "production"); + vi.stubEnv("AUTH_REQUIRE_EMAIL_VERIFICATION", "0"); + const { resolveEmailPasswordAuthPolicy } = + await import("./better-auth-instance.js"); + + expect(resolveEmailPasswordAuthPolicy(true)).toEqual({ + requireEmailVerification: false, + disableSignUp: false, + }); + }, 15_000); + + it("also lifts the hosted no-email signup lock, since it is the same decision", async () => { + vi.stubEnv("NODE_ENV", "production"); + vi.stubEnv("AUTH_REQUIRE_EMAIL_VERIFICATION", "0"); + const { resolveEmailPasswordAuthPolicy } = + await import("./better-auth-instance.js"); + + expect(resolveEmailPasswordAuthPolicy(false)).toEqual({ + requireEmailVerification: false, + disableSignUp: false, + }); + }, 15_000); + + it("outranks AUTH_SKIP_EMAIL_VERIFICATION in local development", async () => { + vi.stubEnv("NODE_ENV", "development"); + vi.stubEnv("AUTH_SKIP_EMAIL_VERIFICATION", "1"); + vi.stubEnv("AUTH_REQUIRE_EMAIL_VERIFICATION", "1"); + const { resolveEmailPasswordAuthPolicy } = + await import("./better-auth-instance.js"); + + expect(resolveEmailPasswordAuthPolicy(true)).toEqual({ + requireEmailVerification: true, + disableSignUp: false, + }); + }, 15_000); + + it("refuses signup when it requires a verification no provider can deliver", async () => { + vi.stubEnv("NODE_ENV", "development"); + vi.stubEnv("AUTH_REQUIRE_EMAIL_VERIFICATION", "1"); + const { resolveEmailPasswordAuthPolicy } = + await import("./better-auth-instance.js"); + + expect(resolveEmailPasswordAuthPolicy(false)).toEqual({ + requireEmailVerification: false, + disableSignUp: true, + }); + }, 15_000); + + it("is settable from defineAppConfig, which beats the env alias", async () => { + vi.stubEnv("NODE_ENV", "production"); + vi.stubEnv("AUTH_REQUIRE_EMAIL_VERIFICATION", "1"); + const { defineAppConfig } = await import("../app-config/index.js"); + defineAppConfig({ auth: { requireEmailVerification: false } }); + const { resolveEmailPasswordAuthPolicy } = + await import("./better-auth-instance.js"); + + expect(resolveEmailPasswordAuthPolicy(true)).toEqual({ + requireEmailVerification: false, + disableSignUp: false, + }); + }, 15_000); + + it("leaves the derived policy alone when it is unset", async () => { + vi.stubEnv("NODE_ENV", "production"); + const { resolveEmailPasswordAuthPolicy } = + await import("./better-auth-instance.js"); + + expect(resolveEmailPasswordAuthPolicy(true)).toEqual({ + requireEmailVerification: true, + disableSignUp: false, + }); + expect(resolveEmailPasswordAuthPolicy(false)).toEqual({ + requireEmailVerification: false, + disableSignUp: true, + }); + }, 15_000); + }); + describe("resolveAuthLoginMode", () => { it("defaults to magic link only when email is ready", async () => { const { resolveAuthLoginMode } = diff --git a/packages/core/src/server/better-auth-instance.ts b/packages/core/src/server/better-auth-instance.ts index f68cdcbe0b..f501fca024 100644 --- a/packages/core/src/server/better-auth-instance.ts +++ b/packages/core/src/server/better-auth-instance.ts @@ -26,6 +26,7 @@ import { integer as sqliteInteger, } from "drizzle-orm/sqlite-core"; +import { getAppConfig } from "../app-config/index.js"; import { TEMPLATES } from "../cli/templates-meta.js"; import { getDbExec, isPostgres } from "../db/client.js"; import { @@ -392,6 +393,19 @@ export function resolveEmailPasswordAuthPolicy(emailConfigured: boolean): { requireEmailVerification: boolean; disableSignUp: boolean; } { + const declared = getAppConfig().auth.requireEmailVerification; + if (declared !== undefined) { + // A declared policy is the whole policy — it outranks both the hosted + // derivation below and AUTH_SKIP_EMAIL_VERIFICATION. Choosing `false` is + // choosing to accept an unverified email as a login credential, so the + // signup lock that exists to prevent exactly that comes off with it. + return { + requireEmailVerification: declared && emailConfigured, + // Verification that no provider can deliver would strand every new + // account on an unverifiable signup, so refuse the signup instead. + disableSignUp: declared && !emailConfigured, + }; + } const hosted = process.env.NODE_ENV === "production" || isDeployPreview(); return { requireEmailVerification: diff --git a/packages/core/src/vite/client.spec.ts b/packages/core/src/vite/client.spec.ts index 24f7ddd4bf..6afb955735 100644 --- a/packages/core/src/vite/client.spec.ts +++ b/packages/core/src/vite/client.spec.ts @@ -1637,6 +1637,38 @@ describe("agentNative Vite plugin preset", () => { }); }); + it("does not re-emit Vite's deprecated rollupOptions alias", async () => { + const plugins = flatPlugins(agentNative()); + const configPlugin = plugins.find((p) => p?.name === "agent-native-config"); + + // Vite 8 hands plugins a config where `rollupOptions` is a getter alias of + // `rolldownOptions`. Spreading it back out alongside our own + // `rolldownOptions` makes Vite warn that this plugin set both. + const aliasSection = (rolldownOptions: unknown) => { + const section: any = { rolldownOptions }; + Object.defineProperty(section, "rollupOptions", { + get: () => section.rolldownOptions, + enumerable: true, + configurable: true, + }); + return section; + }; + + const config = (await configPlugin.config( + { + build: aliasSection({}), + optimizeDeps: aliasSection({ plugins: [{ name: "app-dep-plugin" }] }), + }, + { command: "serve", mode: "development" }, + )) as any; + + expect(Object.hasOwn(config.optimizeDeps, "rollupOptions")).toBe(false); + expect(Object.hasOwn(config.build, "rollupOptions")).toBe(false); + expect( + config.optimizeDeps.rolldownOptions.plugins.map((p: any) => p.name), + ).toEqual(["app-dep-plugin", "agent-native:no-dep-prebundle-sourcemaps"]); + }); + it("restores dep prebundle sourcemaps when AGENT_NATIVE_DEP_SOURCEMAPS=1", async () => { const previous = process.env.AGENT_NATIVE_DEP_SOURCEMAPS; process.env.AGENT_NATIVE_DEP_SOURCEMAPS = "1"; diff --git a/packages/core/src/vite/client.ts b/packages/core/src/vite/client.ts index 889363db1c..67962f5b06 100644 --- a/packages/core/src/vite/client.ts +++ b/packages/core/src/vite/client.ts @@ -3673,6 +3673,15 @@ function createAgentNativeConfig( const forcePollingWatch = process.env.CHOKIDAR_USEPOLLING === "1"; const pollingWatchInterval = Number(process.env.CHOKIDAR_INTERVAL ?? 1000); const userWatch = userConfig.server?.watch ?? {}; + // Vite 8 defines `rollupOptions` on `build`/`optimizeDeps` as a getter alias + // of `rolldownOptions`. Spreading the section copies the alias as a plain own + // property, so returning our own `rolldownOptions` alongside it makes the two + // diverge and Vite warns that this plugin set both — then ignores the + // `rollupOptions` half regardless. Drop the alias from what we spread back. + const { rollupOptions: _buildRollupOptionsAlias, ...userBuild } = + userConfig.build ?? {}; + const { rollupOptions: _depsRollupOptionsAlias, ...userOptimizeDeps } = + userConfig.optimizeDeps ?? {}; return { logLevel: @@ -3788,7 +3797,7 @@ function createAgentNativeConfig( }, }, build: { - ...(userConfig.build ?? {}), + ...userBuild, outDir: options.outDir ?? userConfig.build?.outDir ?? "dist/spa", // Vite 8 defaults CSS minification to Lightning CSS, which collapses a // `backdrop-filter` + `-webkit-backdrop-filter` pair down to only the @@ -3875,7 +3884,7 @@ function createAgentNativeConfig( ], }, optimizeDeps: { - ...(userConfig.optimizeDeps ?? {}), + ...userOptimizeDeps, include: [ ...getDefaultOptimizeDeps(cwd), ...(hasDep("@agent-native/pinpoint", cwd) diff --git a/scripts/guard-env-documentation.ts b/scripts/guard-env-documentation.ts index 8a52c981e1..2509d9444c 100644 --- a/scripts/guard-env-documentation.ts +++ b/scripts/guard-env-documentation.ts @@ -30,6 +30,7 @@ const PUBLIC_EXACT_KEYS = new Set([ "AUTH_DISABLED", "AUTH_MAGIC_LINK", "AUTH_MODE", + "AUTH_REQUIRE_EMAIL_VERIFICATION", "AUTH_SKIP_EMAIL_VERIFICATION", "BRAVE_SEARCH_API_KEY", "BETTER_AUTH_SECRET",