docs: refine warning guidance across plugin docs (#10185)

This commit is contained in:
Taesu
2026-06-21 22:39:30 -07:00
committed by GitHub
parent 461ca6fd24
commit e7c8066cf1
5 changed files with 15 additions and 22 deletions
+2 -2
View File
@@ -128,7 +128,7 @@ and a `ctx` context object as the second parameter.
**expiresIn**: specifies the time in seconds after which the magic link will expire. The default value is `300` seconds (5 minutes).
**allowedAttempts** (deprecated): Each verification call now consumes the token atomically on the first attempt, so retries always fail with `?error=INVALID_TOKEN` regardless of this setting (see [GHSA-hc7v-rggr-4hvx](https://github.com/better-auth/better-auth/security/advisories/GHSA-hc7v-rggr-4hvx)). The option is kept for source compatibility but ignored; multi-attempt redemption is no longer supported. Setting it to any value other than `1` emits a `console.warn` at startup (including `0`, which previously rejected immediately and now has no effect).
**allowedAttempts** (deprecated): Each verification call now consumes the token atomically on the first attempt, so retries always fail with `?error=INVALID_TOKEN` regardless of this setting. The option is kept for source compatibility but ignored; multi-attempt redemption is no longer supported. Setting it to any value other than `1` emits a `console.warn` at startup (including `0`, which previously rejected immediately and now has no effect).
**disableSignUp**: If set to `true`, the user will not be able to sign up using the magic link. The default value is `false`.
@@ -153,5 +153,5 @@ The `storeToken` function can be one of the following:
The storage backend itself is controlled by the global [`verification`](/docs/reference/options#verification) config. If you configure `secondaryStorage`, magic link verification records can be stored there instead of the database.
<Callout type="warn">
When `secondaryStorage` backs verification (`verification.storeInDatabase: false`), the atomic single-use guarantee from [GHSA-hc7v-rggr-4hvx](https://github.com/better-auth/better-auth/security/advisories/GHSA-hc7v-rggr-4hvx) requires your secondary storage to expose `getAndDelete` (Redis `GETDEL`, KV `getAndDelete`). If the implementation only exposes `get` and `delete`, the consume falls back to an in-process JavaScript lock that does not coordinate across multiple application instances. Multi-instance deployments using secondary-storage verification MUST configure a backend that implements `getAndDelete`.
When `secondaryStorage` backs verification (`verification.storeInDatabase: false`), the atomic single-use guarantee requires your secondary storage to expose `getAndDelete` (Redis `GETDEL`, KV `getAndDelete`). If the implementation only exposes `get` and `delete`, the consume falls back to an in-process JavaScript lock that does not coordinate across multiple application instances. Multi-instance deployments using secondary-storage verification MUST configure a backend that implements `getAndDelete`.
</Callout>
@@ -32,9 +32,9 @@ export interface MagicLinkOptions {
* @deprecated Multi-attempt verification is no longer supported. Each
* magic link token is consumed atomically on the first verification call,
* so a given token mints at most one session regardless of this value
* (see GHSA-hc7v-rggr-4hvx). The option is kept for source compatibility
* and may be removed in a future major; any value other than `1` is
* ignored and emits a `console.warn` at plugin construction.
* The option is kept for source compatibility and may be removed in a future
* major; any value other than `1` is ignored and emits a `console.warn` at
* plugin construction.
*
* @default 1
*/
@@ -162,7 +162,7 @@ export const magicLink = (options: MagicLinkOptions) => {
if (options.allowedAttempts !== undefined && options.allowedAttempts !== 1) {
console.warn(
"[better-auth/magic-link] `allowedAttempts` is ignored: tokens are consumed atomically on the first verification call (GHSA-hc7v-rggr-4hvx). Any value other than `1` has no effect; remove the option to silence this warning.",
"[better-auth/magic-link] `allowedAttempts` is ignored: tokens are consumed atomically on the first verification call. Any value other than `1` has no effect; remove the option to silence this warning.",
);
}
@@ -555,13 +555,10 @@ export const mcp = (options: MCPOptions) => {
// caller receives the row; concurrent racers receive `null`
// and fall through to the `invalid_grant` error path.
//
// TODO(legacy-hardening-coordinate): in-flight follow-ups at
// https://github.com/better-auth/better-auth/security/advisories/GHSA-9h47-pqcx-hjr4
// and https://github.com/better-auth/better-auth/security/advisories/GHSA-pw9m-5jxm-xr6h
// touch this same surface. Whoever lands second must rebase
// to keep the atomic consume + `invalid_grant` semantics in
// place; do not regress to a `findVerificationValue` +
// delete pair.
// TODO(legacy-hardening-coordinate): follow-up hardening touches
// this same surface. Whoever lands second must rebase to keep
// the atomic consume + `invalid_grant` semantics in place; do
// not regress to a `findVerificationValue` + delete pair.
const verificationValue =
await ctx.context.internalAdapter.consumeVerificationValue(
code.toString(),
@@ -880,13 +880,10 @@ export const oidcProvider = (options: OIDCOptions) => {
// caller receives the row; concurrent racers receive `null`
// and fall through to the `invalid_grant` error path.
//
// TODO(legacy-hardening-coordinate): in-flight follow-ups at
// https://github.com/better-auth/better-auth/security/advisories/GHSA-9h47-pqcx-hjr4
// and https://github.com/better-auth/better-auth/security/advisories/GHSA-pw9m-5jxm-xr6h
// touch this same surface. Whoever lands second must rebase
// to keep the atomic consume + `invalid_grant` semantics in
// place; do not regress to a `findVerificationValue` +
// delete pair.
// TODO(legacy-hardening-coordinate): follow-up hardening touches
// this same surface. Whoever lands second must rebase to keep
// the atomic consume + `invalid_grant` semantics in place; do
// not regress to a `findVerificationValue` + delete pair.
const verificationValue =
await ctx.context.internalAdapter.consumeVerificationValue(
code.toString(),
+1 -2
View File
@@ -87,8 +87,7 @@ function resolveRequiredRoles(
// TODO(scim-provider-ownership-default-on): flip default to `true` on next so
// new non-org SCIM tokens are owner-locked by default. Coupled with the
// `scimProvider.userId` schema column. Tracks the SCIM provider-ownership
// advisory.
// `scimProvider.userId` schema column.
function isProviderOwnershipEnabled(opts: SCIMOptions): boolean {
return opts.providerOwnership?.enabled ?? false;
}