Skip to Content
Delmare Digital

betterAuthStrategy

The Payload auth strategy that validates Better Auth sessions, API keys and OAuth bearer tokens on every Payload request.

betterAuthStrategy(options?) is a Payload auth strategy. Add it to your users collection with the local strategy disabled:

src/collections/Users/index.ts
import { betterAuthStrategy } from '@delmaredigital/payload-better-auth'

auth: {
  disableLocalStrategy: true,
  strategies: [betterAuthStrategy()],
},

On each request it calls Better Auth's getSession(), which accepts a session cookie or, with the api-key plugin, an API key. If that finds no session, it tries an OAuth JWT bearer token. The resolved user gets the session fields and, with organizations, the member's organizationRole.

Options

Prop

Type

Session refresh

When Payload lets the strategy set headers (REST and GraphQL requests), it forwards Better Auth's refreshed Set-Cookie through Payload's responseHeaders. When it can't (canSetHeaders: false, for example admin server renders), the session is read with disableRefresh. See Sliding sessions.

API keys

API keys are sent as x-api-key, which is what Better Auth's api-key plugin reads by default. Authorization: Bearer <key> is only treated as an API key if you configure the plugin's apiKeyHeaders or customAPIKeyGetter; otherwise such a request authenticates as nobody.

A key's permissions are flattened into req.user.apiKeyScopes (for example ['posts:read', 'posts:write']), which the permission helpers read.

OAuth bearer tokens

With no session, an Authorization: Bearer JWT is verified with Better Auth's verifyBearerToken. The user is loaded by the token's sub, with the token's scopes on req.user.oauthScopes and its organizationId, if any, as activeOrganizationId. DPoP-bound (RFC 9449) tokens are rejected here by design, because Payload hands the strategy only headers, with no method or URL.

Edit this page on GitHub

On this page