betterauth

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 28 Imported by: 0

README

better-auth-go

better-auth-go is an embeddable authentication server library for Go. It owns authentication state and exposes a standard net/http handler; it is not a client SDK and does not require a Node or Bun service.

The public server and adapter contracts track Better Auth TypeScript v1.6 while using native Go security defaults:

  • Better Auth-compatible core route names under /api/auth;
  • email/password sign-up, sign-in, password change, verified email change, opt-in deletion, sign-out, session listing/rotation/revocation, and account linking/unlinking;
  • password reset and email verification with single-use hash-at-rest tokens;
  • Better Auth's 35 built-in social-provider IDs plus generic OAuth2/OIDC;
  • authorization-gated, one-hour maximum admin impersonation with durable audit;
  • Argon2id password hashes and an injected migration verifier for legacy scrypt;
  • opaque 256-bit session tokens with only SHA-256 hashes persisted;
  • concurrency-safe in-process session resolution for application handlers, without HTTP or JSON loopback;
  • host-only __Host- Secure HttpOnly SameSite cookies;
  • exact, bounded wildcard, or request-resolved trusted-origin policy; CSRF, callback allowlist, request-size, and rate-limit enforcement;
  • Better Auth-aligned generic database adapters, schema extensions, model/field mappings, transactions, atomic consume, and guarded increments;
  • MongoDB, PostgreSQL, SQLite, a public adapter conformance suite, and an in-memory development adapter.
  • an opt-in Better Auth-shaped passkey/WebAuthn plugin with hash-at-rest, single-use challenges and fixation-safe core session rotation;
  • an opt-in Better Auth-shaped 2FA plugin with encrypted TOTP/backup material, delivered OTP, trusted devices, shared attempt budgets, and durable lockout.

The v1 stability guarantee covers the core server and first-party MongoDB, PostgreSQL, and SQLite adapters. Packages below plugin/, including SSO and SCIM, remain experimental and outside that guarantee. Review Versioning and stability, the compatibility matrix, and the changelog before upgrading.

The pinned cross-runtime suite is reproducible from this repository:

cd compat/typescript-oracle
bun install --frozen-lockfile
cd ../..
scripts/test-typescript-compat.sh

Install

go get github.com/eadwinCode/better-auth-go

Production deployments should pin an exact released tag. The release workflow tests installation from an external module without a local replace directive.

Minimal server

package main

import (
	"context"
	"log"
	"net/http"

	betterauth "github.com/eadwinCode/better-auth-go"
	"github.com/eadwinCode/better-auth-go/adapter/mongodb"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
)

type mailer struct{}

func (mailer) Send(context.Context, betterauth.Mail) error {
	// Deliver through your transactional provider. Never log message.Token.
	return nil
}

type adminPolicy struct{}

func (adminPolicy) CanImpersonate(context.Context, betterauth.User, betterauth.User) error {
	// Replace with an application authorization decision.
	return betterauth.ErrNotFound
}

func main() {
	ctx := context.Background()
	client, err := mongo.Connect(options.Client().ApplyURI("mongodb://localhost:27017"))
	if err != nil {
		log.Fatal(err)
	}
	database, err := mongodb.New(mongodb.Config{Database: client.Database("app")})
	if err != nil {
		log.Fatal(err)
	}
	auth, err := betterauth.New(betterauth.Config{
		PublicURL:               "https://auth.example.com",
		TrustedOrigins:          []string{"https://app.example.com"},
		Database:                database,
		Mailer:                  mailer{},
		ImpersonationAuthorizer: adminPolicy{},
	})
	if err != nil {
		log.Fatal(err)
	}
	if err := database.EnsureIndexes(ctx, auth.Schema()); err != nil {
		log.Fatal(err)
	}
	log.Fatal(http.ListenAndServe(":8080", auth.Handler()))
}

The full runnable example is in examples/nethttp.

Mounting

Handler() accepts full request paths. With the default configuration it serves under /api/auth. To share a mux:

mux := http.NewServeMux()
mux.Handle("/api/auth/", auth.Handler())

Set Config.BasePath to mount elsewhere. Route paths do not contain an extra Go specific version segment.

Resolving sessions in application handlers

Use ResolveSession when an application route needs the current identity without an HTTP/JSON call back into the auth handler:

result, err := auth.ResolveSession(r.Context(), r)
switch {
case errors.Is(err, betterauth.ErrNoSession):
	http.Error(w, "authentication required", http.StatusUnauthorized)
	return
case err != nil:
	http.Error(w, "service unavailable", http.StatusServiceUnavailable)
	return
}
user := result.User
session := result.Session

The method uses the configured session-cookie name and is safe for concurrent requests. Missing, invalid, expired, or revoked sessions and disabled users match ErrNoSession; database and adapter failures remain distinct. It is a read-only resolver and does not run HTTP hooks, CSRF/origin policy, rotate sessions, set cookies, or return the raw token. See In-process session resolution for the full API and error contract.

Email and password options

The production-sensitive Better Auth v1.6 options are grouped under Config.EmailPassword:

autoSignIn := false
config.EmailPassword = betterauth.EmailPasswordConfig{
	DisableSignUp:                 false,
	AutoSignIn:                    &autoSignIn,
	RequireEmailVerification:      true,
	RevokeSessionsOnPasswordReset: true,
}

AutoSignIn is optional so its omitted value can preserve Better Auth's true default. Requiring verification or disabling automatic sign-in produces a sessionless signup and enables synthetic duplicate responses that do not reveal whether the email already exists. Required verification sends the configured mailer's single-use verification message and blocks credential sign-in until it is consumed.

Password reset does not sign in the reset browser. Better Auth's compatible default preserves existing sessions; set RevokeSessionsOnPasswordReset when a reset must terminate every device. Passwords default to 8–128 bytes, and reset and verification tokens default to a one-hour lifetime. Applications can override the existing MinPasswordBytes, MaxPasswordBytes, PasswordResetTTL, and EmailVerificationTTL fields.

The remaining Better Auth 1.6 lifecycle callbacks and delivery modes are available through Config.EmailVerification, Config.EmailPassword, and Config.User:

sendOnSignUp := true
config.EmailVerification = betterauth.EmailVerificationConfig{
	SendOnSignUp:                &sendOnSignUp,
	SendOnSignIn:                true,
	AutoSignInAfterVerification: true,
	BeforeVerification:          beforeVerification,
	AfterVerification:           afterVerification,
}
config.EmailPassword.OnPasswordReset = onPasswordReset
config.EmailPassword.OnExistingUserSignUp = onExistingUserSignUp
config.EmailPassword.CustomSyntheticUser = syntheticUserFactory
config.User.SendChangeEmailConfirmation = true
config.User.UpdateEmailWithoutVerification = false

SendOnSignUp is tri-state: when omitted, it follows RequireEmailVerification. Existing-user signup callbacks run through the configured background-task runner and never alter the synthetic, enumeration-resistant response. Change-email confirmation sends first to the verified old inbox and only then sends the single-use verification link to the new inbox.

Social providers

Construct providers with social.New and register them by Better Auth provider ID:

google, err := social.New("google", social.Options{
	ClientID:     os.Getenv("GOOGLE_CLIENT_ID"),
	ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
})
if err != nil {
	return err
}

cipher, err := betterauth.NewAESGCMTokenCipher(providerTokenKey)
if err != nil {
	return err
}

config.SocialProviders = map[string]betterauth.OAuthProvider{
	"google": google,
}
config.AllowedRedirectURLs = []string{
	"https://app.example.com/auth/complete",
}
config.ProviderTokenCipher = cipher

Supported built-in IDs are exported as social.SupportedProviders. Custom OAuth2 providers use the same constructor with explicit authorization, token, and user-info URLs. Provider endpoints must be HTTPS, provider HTTP clients are bounded and refuse redirects, OIDC ID tokens validate signature/issuer/audience/ expiry/nonce, and provider credentials are encrypted before persistence.

Generic OIDC providers use discovery:

enterprise, err := social.NewOIDC(ctx, "enterprise-oidc", social.Options{
	ClientID:     os.Getenv("OIDC_CLIENT_ID"),
	ClientSecret: os.Getenv("OIDC_CLIENT_SECRET"),
	Issuer:       "https://identity.example.com",
})

Discovery pins the returned issuer, validates authorization/token/user-info/ JWKS endpoints, requires authorization-code and RS256 support when advertised, rejects redirects and private literal endpoints, and applies the same timeout and response-size limits as preset providers.

Some providers do not assert a verified email. They can authenticate a stable provider account, but automatic email linking remains blocked until the application supplies a trustworthy verification/collection policy through a custom profile mapper. This is a deliberate account-takeover defense.

Passkeys

Passkeys are opt-in and remain a normal server plugin:

import "github.com/eadwinCode/better-auth-go/plugin/passkey"

passkeys, err := passkey.New(passkey.Config{
	RPID:          "example.com",
	RPDisplayName: "Example",
	Origins:       []string{"https://app.example.com"},
})
if err != nil {
	return err
}
config.Plugins = append(config.Plugins, passkeys)

The default requires authenticator user verification. Set UserVerification: passkey.VerificationPreferred only when compatibility with authenticators that cannot assert UV is an explicit product decision. RP ID and origins are exact construction-time policy; request headers cannot expand them.

The HTTP flow matches Better Auth's generate/verify registration and authentication routes, plus list, rename, and delete. WebAuthn challenges are represented in the browser by a secure __Host- cookie, stored only as a hash, and atomically consumed. See the passkey guide and ADR 0004.

Two-factor authentication

Two-factor authentication is an isolated server plugin:

import "github.com/eadwinCode/better-auth-go/plugin/twofactor"

cipher, err := betterauth.NewAESGCMTokenCipher(twoFactorKey)
if err != nil {
	return err
}
twoFactor, err := twofactor.New(twofactor.Config{
	Issuer: "Example",
	Cipher: cipher,
	DeliverOTP: func(
		ctx *betterauth.HookContext,
		user betterauth.User,
		code string,
	) error {
		return deliverOTP(ctx.Context, user, code)
	},
})
if err != nil {
	return err
}
config.Plugins = append(config.Plugins, twoFactor)

The plugin provides Better Auth's enable/disable, TOTP, delivered OTP, backup code, trusted-device, and credential-sign-in challenge flows. Secret material is encrypted, opaque challenge/device values are hash-only at rest, and the first-factor session is revoked before a 2FA redirect is returned. See the 2FA guide and ADR 0005.

Server plugins and hooks

Config.Plugins provides the Better Auth-style server extension lifecycle: plugin initialization and dependencies, schema, exact and parameterized endpoints, endpoint and route middleware, before/after hooks, global OnRequest/OnResponse, trusted origins, rate-limit rules, database hooks, and background tasks. Config.Hooks provides the same global lifecycle for application-owned customization without manufacturing a plugin.

auditPlugin := betterauth.Plugin{
	ID: "audit",
	TrustedOrigins: []string{"https://admin.example.com"},
	Endpoints: []betterauth.PluginEndpoint{{
		Name: "get-event",
		Path: "/audit/events/:id",
		Method: http.MethodGet,
		QueryValidator: betterauth.ObjectValidator{
			Fields: map[string]betterauth.FieldValidation{
				"expand": {Kind: betterauth.ValidationBoolean},
			},
		},
		Use: []betterauth.RequestHook{betterauth.SessionMiddleware},
		Handler: func(ctx *betterauth.HookContext) (*betterauth.PluginResponse, error) {
			return betterauth.JSONResponse(http.StatusOK, map[string]string{
				"id": ctx.Params["id"],
			})
		},
	}},
	OnResponse: func(ctx *betterauth.HookContext, response *betterauth.PluginResponse) error {
		response.Headers.Set("X-Auth-Plugin", ctx.PluginID)
		return nil
	},
}
config.Plugins = []betterauth.Plugin{auditPlugin}

For state-changing API requests, trusted-origin enforcement runs before plugin code. Plugins may contribute exact or HTTPS hostname-pattern origins. Applications may inject a request-scoped TrustedOriginResolver for bounded multi-tenant policy; its static and dynamic results are additive, pass the same validation, and fail closed on errors or panics. Resolver implementations must not trust unvalidated Host or forwarding headers. Neither plugins nor response hooks can remove mandatory no-store/security headers. Protocol endpoints that authenticate without browser credentials may use an explicit construction-time origin exception; this does not bypass their middleware, validators, hooks, rate limits, or response hooks. Plugin descriptors are copied during New; callbacks must be concurrency-safe and must not retain request-scoped HookContext values. Plugin cookies can be appended with PluginResponse.SetCookie, which enforces Secure, HttpOnly, SameSite, host-only __Host- cookies. Cookie-authenticated mutation endpoints should use both SessionMiddleware and CSRFMiddleware; origin enforcement remains mandatory independently. Endpoint BodyValidator and QueryValidator declarations run after OnRequest and rate limiting but before middleware, before-hooks, and endpoint code. ObjectValidator is dependency-free; EndpointValidatorFunc can bridge an application's existing validation package. Wildcard origins allow * and ? only in an HTTPS hostname, for example https://*.example.com; paths, credentials, wildcard ports, IP patterns, and public-suffix patterns are rejected. Exact HTTP origins remain restricted to loopback development addresses. The default background runner waits inline; inject Config.BackgroundTasks when work should be handed to a durable asynchronous queue.

See ADR 0002 and the plugin compatibility checklist. The feature gap register separately tracks endpoint-contract deltas and every built-in plugin family so kernel support is never reported as feature parity.

Database adapters

The DatabaseAdapter API maps Better Auth's adapter operations:

Create, FindOne, FindMany, Count, Update, UpdateMany, Delete, DeleteMany, ConsumeOne, IncrementOne, and Transaction.

Adapters declare value, ID, join, and transaction capabilities. The schema wrapper maps logical model/field names and transforms JSON, dates, booleans, and arrays when the database lacks native types. Run the public conformance suite:

func TestAdapter(t *testing.T) {
	adaptertest.Run(t, func(t *testing.T) betterauth.DatabaseAdapter {
		return newYourAdapter(t)
	})
}

MongoDB uses native findOneAndDelete, guarded findOneAndUpdate, unique/TTL indexes, and transactions. Multi-document core flows require a replica set or sharded cluster.

PostgreSQL and SQLite use the shared database/sql implementation. The application owns the driver and connection pool. Migration is explicit and additive:

database, err := sql.Open("sqlite", sqliteDSN) // import your chosen driver
if err != nil {
	return err
}
adapter, err := sqlite.New(database)
if err != nil {
	return err
}
config.Database = adapter
auth, err := betterauth.New(config)
if err != nil {
	return err
}
if err := adapter.Migrate(ctx, auth.Schema()); err != nil {
	return err
}

Use adapter/postgresql.New with a PostgreSQL *sql.DB. Migrate runs in a transaction, creates missing tables/indexes, adds missing nullable columns, and never drops data. A newly required column on a populated table fails closed so the application can perform an explicit backfill migration.

Email change and user deletion are disabled until Config.User.ChangeEmailEnabled and Config.User.DeleteUserEnabled are set. The former verifies the new inbox with a single-use token; credential-user deletion requires password reauthentication. Setting Config.User.SendDeleteAccountVerification makes deletion send an account-deletion mail with a single-use callback token instead. Applications may use Config.User.BeforeDelete and Config.User.AfterDelete for lifecycle work; the before hook can stop deletion, while the after hook runs only after the account and authentication records have been durably removed.

Password migration

Argon2id is canonical for new passwords. To import Better Auth scrypt records, implement PasswordVerifier as a bridge:

  1. recognize and verify the legacy format with strict parameter bounds;
  2. return PasswordVerification{Valid: true, ReplacementHash: argonHash};
  3. let sign-in atomically replace the old hash.

Legacy compatibility is opt-in; new records are never written in the legacy format.

Security model

Read SECURITY.md and docs/adr/0001-auth-server-architecture.md before deploying. Important operational requirements:

  • terminate TLS before requests reach the application;
  • preserve Secure and __Host- cookie rules;
  • prefer exact trusted origins and configure exact redirect URLs; keep any wildcard or request-resolved origin policy tenant-bound and narrow;
  • do not enable proxy-header trust unless a trusted proxy overwrites them;
  • keep provider-token encryption keys outside source control and rotate through an application key-ring implementation;
  • run MongoDB as a replica set or sharded cluster;
  • treat mail links, OAuth codes, cookies, and raw tokens as secrets;
  • consume outbox events idempotently.

The complete deployment, backup/restore, proxy/cookie, key-rotation, and upgrade runbook is in Production operations.

Compatibility and roadmap

The stable server plugin kernel and experimental passkey, two-factor, organization, enterprise SSO, and SCIM feature packages are implemented. Username, magic links, API keys, and other feature plugins remain separate compatibility milestones with their own threat models.

License

MIT

Documentation

Overview

Package betterauth provides an embeddable, net/http-compatible authentication server for Go applications.

Index

Constants

View Source
const (
	ModelUser         = "user"
	ModelSession      = "session"
	ModelAccount      = "account"
	ModelVerification = "verification"
	ModelAuditEvent   = "auditEvent"
	ModelOutboxEvent  = "outboxEvent"
)
View Source
const (
	PurposePasswordReset           OneTimePurpose = "password_reset"
	PurposeEmailVerify             OneTimePurpose = "email_verify"
	PurposeEmailChange             OneTimePurpose = "email_change"
	PurposeEmailChangeConfirmation OneTimePurpose = "email_change_confirmation"
	PurposeUserDeletion            OneTimePurpose = "user_deletion"
	PurposeOAuthState              OneTimePurpose = "oauth_state"
	ProviderGoogle                                = "google"
	EventUserCreated                              = "user.created"
	AuditImpersonationStart                       = "admin.impersonation.started"
	AuditImpersonationStop                        = "admin.impersonation.stopped"
)
View Source
const (
	// APIVersion is the stable HTTP API version implemented by this module.
	APIVersion = "v1"
	// Version is the library's semantic version. It is replaced by the release
	// process for tagged builds.
	Version = "0.1.0-dev"
)

Variables

View Source
var (
	// ErrNotFound is returned by adapters for absent records.
	ErrNotFound = errors.New("betterauth: not found")
	// ErrConflict is returned when a unique identity already exists.
	ErrConflict = errors.New("betterauth: conflict")
	// ErrReplay is returned when a single-use value was already consumed.
	ErrReplay = errors.New("betterauth: replay")
	// ErrAccountNotLinked is returned when a same-email OAuth identity exists
	// but the configured implicit-linking policy denies attaching it.
	ErrAccountNotLinked = errors.New("betterauth: account not linked")
	// ErrSignUpDisabled is returned when an OAuth provider is allowed to sign
	// in existing identities but not create a new user for this request.
	ErrSignUpDisabled = errors.New("betterauth: oauth sign up disabled")
)
View Source
var ErrNoSession = errors.New("betterauth: no session")

ErrNoSession means the request does not carry a currently valid session. It covers missing or invalid cookies, absent users or sessions, expired or revoked sessions, and disabled users.

Functions

func HashToken

func HashToken(raw string) string

HashToken returns a fixed-size, URL-safe representation suitable for storage.

Types

type AESGCMTokenCipher

type AESGCMTokenCipher struct {
	// contains filtered or unexported fields
}

func NewAESGCMTokenCipher

func NewAESGCMTokenCipher(key []byte) (*AESGCMTokenCipher, error)

func (*AESGCMTokenCipher) Open

func (c *AESGCMTokenCipher) Open(_ context.Context, encoded string) (string, error)

func (*AESGCMTokenCipher) Seal

func (c *AESGCMTokenCipher) Seal(_ context.Context, plaintext string) (string, error)

type AccountManagementConfig

type AccountManagementConfig struct {
	// UpdateAccountOnSignIn controls whether returning-provider sign-in writes
	// the latest provider tokens. Nil defaults to true.
	UpdateAccountOnSignIn *bool
	// LinkingEnabled controls explicit and implicit provider linking. Nil
	// defaults to true, matching Better Auth v1.6.
	LinkingEnabled *bool
	// DisableImplicitLinking prevents a social sign-in from attaching a new
	// provider identity to an existing same-email user. Explicit link-social
	// remains available when linking itself is enabled.
	DisableImplicitLinking bool
	// TrustedProviders is an immutable allowlist whose configured provider is
	// accepted as verified identity evidence even when its profile omits an
	// emailVerified flag.
	TrustedProviders []string
	// TrustedProviderResolver is the request-dependent v1.6 alternative to the
	// static TrustedProviders list. Configuring both fails closed.
	TrustedProviderResolver TrustedProviderResolver
	// RequireLocalEmailVerified protects implicit same-email linking. Nil
	// defaults to true.
	RequireLocalEmailVerified *bool
	// UpdateUserInfoOnLink copies non-identity name/image fields from a newly
	// linked provider profile. Email and verification state are never changed.
	UpdateUserInfoOnLink bool
	// AllowUnlinkingAll permits removal of the final sign-in method. The secure
	// default is false so a user cannot accidentally make their account
	// unreachable.
	AllowUnlinkingAll bool
	// AllowLinkingDifferentEmails permits an authenticated user to link a
	// provider identity whose verified email differs from the current user.
	AllowLinkingDifferentEmails bool
}

type AdapterCapabilities

type AdapterCapabilities struct {
	JSON         bool
	Dates        bool
	Booleans     bool
	Arrays       bool
	NumericIDs   bool
	UUIDs        bool
	Joins        bool
	Transactions bool
}

AdapterCapabilities describe native storage behavior.

type AdminConfig

type AdminConfig struct {
	DefaultRole              string
	AdminRoles               []string
	AdminUserIDs             []string
	RoleResolver             AdminRoleResolver
	AllowImpersonatingAdmins bool
}

AdminConfig provides the Better Auth v1.6 administrator-selection options that govern core impersonation. Full admin CRUD/ban endpoints remain a separate plugin surface.

type AdminRoleResolver

type AdminRoleResolver interface {
	Roles(context.Context, User) ([]string, error)
}

AdminRoleResolver returns application-owned roles for one user. It is invoked per request and must be concurrency-safe; roles are never cached on the shared server.

type Argon2Params

type Argon2Params struct {
	Memory      uint32
	Iterations  uint32
	Parallelism uint8
	SaltLength  uint32
	KeyLength   uint32
}

func DefaultArgon2Params

func DefaultArgon2Params() Argon2Params

type Argon2idVerifier

type Argon2idVerifier struct {
	Params      Argon2Params
	MaxPassword int
}

Argon2idVerifier is the native password format.

func NewArgon2idVerifier

func NewArgon2idVerifier(params Argon2Params, maxPassword int) (*Argon2idVerifier, error)

func (*Argon2idVerifier) Hash

func (v *Argon2idVerifier) Hash(_ context.Context, password string) (string, error)

func (*Argon2idVerifier) Verify

func (v *Argon2idVerifier) Verify(ctx context.Context, encoded, password string) (PasswordVerification, error)

type AuditEvent

type AuditEvent struct {
	ID            string
	SchemaVersion int
	Action        string
	ActorUserID   string
	SubjectUserID string
	SessionID     string
	OccurredAt    time.Time
	Request       RequestMetadata
	Details       map[string]string
}

AuditEvent is an append-only security record.

type BackgroundTask

type BackgroundTask func(context.Context) error

BackgroundTask is submitted through an application-owned runner. The request context passed to Submit is detached from cancellation before Run.

type BackgroundTaskRunner

type BackgroundTaskRunner interface {
	Submit(context.Context, BackgroundTask) error
}

BackgroundTaskRunner accepts request-detached non-critical work.

type ChangePasswordParams

type ChangePasswordParams struct {
	UserID              string
	PreviousHash        string
	ReplacementHash     string
	CurrentTokenHash    string
	ReplacementSession  Session
	RevokeOtherSessions bool
}

type Clock

type Clock interface {
	Now() time.Time
}

Clock enables deterministic expiry and audit tests.

type Config

type Config struct {
	BasePath                string
	PublicURL               string
	TrustedOrigins          []string
	TrustedOriginResolver   TrustedOriginResolver
	Database                DatabaseAdapter
	Schema                  Schema
	Mailer                  Mailer
	RateLimiter             RateLimiter
	ImpersonationAuthorizer ImpersonationAuthorizer
	Passwords               PasswordVerifier
	Clock                   Clock
	Tokens                  TokenSource
	ProviderTokenCipher     TokenCipher
	SocialProviders         map[string]OAuthProvider
	AllowedRedirectURLs     []string
	Cookie                  CookieConfig
	Account                 AccountManagementConfig
	Admin                   AdminConfig
	User                    UserManagementConfig
	EmailPassword           EmailPasswordConfig
	EmailVerification       EmailVerificationConfig
	SessionDuration         time.Duration
	SessionFreshAge         time.Duration
	ImpersonationDuration   time.Duration
	PasswordResetTTL        time.Duration
	EmailVerificationTTL    time.Duration
	DeleteUserTTL           time.Duration
	OAuthStateTTL           time.Duration
	ProviderTimeout         time.Duration
	MaxRequestBytes         int64
	MinPasswordBytes        int
	MaxPasswordBytes        int
	TrustProxyHeaders       bool
	Plugins                 []Plugin
	Hooks                   ServerHooks
	BackgroundTasks         BackgroundTaskRunner
	MaxResponseBytes        int64
}

type CookieConfig

type CookieConfig struct {
	Name     string
	CSRFName string
	Path     string
	SameSite http.SameSite
}

type CountQuery

type CountQuery struct {
	Model string
	Where []Where
}

type CreateEmailUserParams

type CreateEmailUserParams struct {
	User          User
	PasswordHash  string
	Session       Session
	CreateSession bool
	Event         DomainEvent
}

type CreateQuery

type CreateQuery struct {
	Model        string
	Data         Record
	Select       []string
	ForceAllowID bool
}

type CryptoTokenSource

type CryptoTokenSource struct{}

func (CryptoTokenSource) Token

func (CryptoTokenSource) Token(byteLength int) (string, error)

type DatabaseAdapter

DatabaseAdapter follows Better Auth's database adapter vocabulary. Single-row update/delete methods reject an empty predicate.

func WrapDatabaseAdapter

func WrapDatabaseAdapter(inner DatabaseAdapter, schema Schema) (DatabaseAdapter, error)

WrapDatabaseAdapter applies model/field mapping and capability-aware value transforms to an adapter. Server construction applies this automatically.

type DatabaseHook

type DatabaseHook struct {
	Model      string
	Operations []DatabaseOperation
	Before     DatabaseHookHandler
	After      DatabaseHookHandler
}

DatabaseHook registers mutation callbacks for one model or "*" and an optional operation allowlist.

type DatabaseHookContext

type DatabaseHookContext struct {
	Operation DatabaseOperation
	Model     string
	Where     []Where
	Data      Record
	Increment map[string]float64
	Result    Record
	Count     int64
}

DatabaseHookContext contains cloned inputs and outputs for one adapter mutation. Before hooks may replace Where, Data, and Increment.

type DatabaseHookHandler

type DatabaseHookHandler func(context.Context, *DatabaseHookContext) error

DatabaseHookHandler handles one logical adapter mutation.

type DatabaseOperation

type DatabaseOperation string

DatabaseOperation identifies a logical adapter mutation.

const (
	DatabaseCreate       DatabaseOperation = "create"
	DatabaseUpdate       DatabaseOperation = "update"
	DatabaseUpdateMany   DatabaseOperation = "updateMany"
	DatabaseDelete       DatabaseOperation = "delete"
	DatabaseDeleteMany   DatabaseOperation = "deleteMany"
	DatabaseConsumeOne   DatabaseOperation = "consumeOne"
	DatabaseIncrementOne DatabaseOperation = "incrementOne"
)

Supported database hook operations.

type DeleteQuery

type DeleteQuery struct {
	Model string
	Where []Where
}

type DomainEvent

type DomainEvent struct {
	ID            string
	SchemaVersion int
	Name          string
	AggregateID   string
	OccurredAt    time.Time
	Payload       map[string]string
}

DomainEvent is persisted to an outbox for idempotent consumers.

type EmailPasswordConfig

type EmailPasswordConfig struct {
	// DisableSignUp rejects new email/password registrations.
	DisableSignUp bool
	// AutoSignIn controls session creation after signup. Nil defaults to true.
	// New copies the pointed-to value so later caller mutation cannot change a
	// running server.
	AutoSignIn *bool
	// RequireEmailVerification suppresses signup sessions and blocks credential
	// sign-in until the single-use verification token is consumed.
	RequireEmailVerification bool
	// RevokeSessionsOnPasswordReset atomically revokes every active user
	// session when a reset token is consumed. Better Auth defaults to false.
	RevokeSessionsOnPasswordReset bool
	// OnPasswordReset runs after the password is durably replaced and before
	// optional session revocation.
	OnPasswordReset UserLifecycleHook
	// OnExistingUserSignUp receives an existing user only through the
	// application-owned background runner. Its result never changes the
	// enumeration-resistant synthetic response.
	OnExistingUserSignUp UserLifecycleHook
	// CustomSyntheticUser adds application-defined public fields to protected
	// duplicate-signup responses.
	CustomSyntheticUser SyntheticUserFactory
}

EmailPasswordConfig controls the Better Auth v1.6 email/password lifecycle. AutoSignIn is optional because the upstream default is true.

type EmailVerificationConfig

type EmailVerificationConfig struct {
	SendOnSignUp                *bool
	SendOnSignIn                bool
	AutoSignInAfterVerification bool
	BeforeVerification          UserLifecycleHook
	AfterVerification           UserLifecycleHook
}

EmailVerificationConfig controls the Better Auth v1.6 verification lifecycle. SendOnSignUp is optional because its default follows EmailPassword.RequireEmailVerification.

type EndpointValidator

type EndpointValidator interface {
	Validate(any) error
}

EndpointValidator validates a decoded endpoint input. Body validators receive JSON-compatible values; query validators receive url.Values. Implementations must be concurrency-safe.

type EndpointValidatorFunc

type EndpointValidatorFunc func(any) error

EndpointValidatorFunc adapts a function to EndpointValidator.

func (EndpointValidatorFunc) Validate

func (validator EndpointValidatorFunc) Validate(value any) error

type Error

type Error struct {
	Code       ErrorCode     `json:"code"`
	Message    string        `json:"message"`
	Status     int           `json:"-"`
	RetryAfter time.Duration `json:"-"`
	RequestID  string        `json:"requestId,omitempty"`
	// contains filtered or unexported fields
}

Error is a structured public-safe authentication error.

func NewError

func NewError(code ErrorCode, message string, status int, cause error) *Error

NewError creates a structured public-safe error for application hooks and feature plugins. Message is returned to the caller and therefore must not contain secrets, database details, or cryptographic verification errors.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorCode

type ErrorCode string
const (
	CodeBadRequest              ErrorCode = "bad_request"
	CodeValidation              ErrorCode = "validation_error"
	CodeInvalidEmail            ErrorCode = "invalid_email"
	CodePasswordTooShort        ErrorCode = "password_too_short"
	CodePasswordTooLong         ErrorCode = "password_too_long"
	CodeInvalidCredentials      ErrorCode = "invalid_credentials"
	CodeEmailNotVerified        ErrorCode = "email_not_verified"
	CodeEmailMismatch           ErrorCode = "email_mismatch"
	CodeEmailAlreadyVerified    ErrorCode = "email_already_verified"
	CodeInvalidPassword         ErrorCode = "invalid_password"
	CodeCredentialNotFound      ErrorCode = "credential_account_not_found"
	CodeAccountNotFound         ErrorCode = "account_not_found"
	CodeUnlinkLastAccount       ErrorCode = "failed_to_unlink_last_account"
	CodeLinkingNotAllowed       ErrorCode = "linking_not_allowed"
	CodeLinkingDifferentEmails  ErrorCode = "linking_different_emails_not_allowed"
	CodeAccountLinkedElsewhere  ErrorCode = "account_already_linked_to_different_user"
	CodeAccountNotLinked        ErrorCode = "account_not_linked"
	CodeOAuthSignUpDisabled     ErrorCode = "oauth_sign_up_disabled"
	CodeProviderNotSupported    ErrorCode = "provider_not_supported"
	CodeTokenRefreshUnsupported ErrorCode = "token_refresh_not_supported"
	CodeRefreshTokenNotFound    ErrorCode = "refresh_token_not_found"
	CodeFailedRefreshToken      ErrorCode = "failed_to_refresh_access_token"
	CodeSignUpDisabled          ErrorCode = "email_password_sign_up_disabled"
	CodeUserAlreadyExists       ErrorCode = "user_already_exists_use_another_email"
	CodeUnauthorized            ErrorCode = "unauthorized"
	CodeForbidden               ErrorCode = "forbidden"
	CodeCannotImpersonateAdmins ErrorCode = "cannot_impersonate_admins"
	CodeCannotImpersonateUsers  ErrorCode = "cannot_impersonate_users"
	CodeSessionNotFresh         ErrorCode = "session_not_fresh"
	CodeNotFound                ErrorCode = "not_found"
	CodeConflict                ErrorCode = "conflict"
	CodeRateLimited             ErrorCode = "rate_limited"
	CodeInvalidOrigin           ErrorCode = "invalid_origin"
	CodeInvalidCSRF             ErrorCode = "invalid_csrf"
	CodeInvalidToken            ErrorCode = "invalid_or_expired_token"
	CodeProviderFailure         ErrorCode = "provider_failure"
	CodeMethodNotAllowed        ErrorCode = "method_not_allowed"
	CodeInternal                ErrorCode = "internal_error"
)

type EventHandler

type EventHandler interface {
	HandleEvent(context.Context, DomainEvent) error
}

EventHandler receives durable, versioned outbox events. Delivery is at-least-once; handlers must use DomainEvent.ID as their idempotency key.

type FieldSchema

type FieldSchema struct {
	Type       FieldType
	Required   bool
	Unique     bool
	Index      bool
	References string
	Input      bool
	Returned   bool
	FieldName  string
}

type FieldType

type FieldType string
const (
	FieldString      FieldType = "string"
	FieldNumber      FieldType = "number"
	FieldBoolean     FieldType = "boolean"
	FieldDate        FieldType = "date"
	FieldJSON        FieldType = "json"
	FieldStringArray FieldType = "string[]"
)

type FieldValidation

type FieldValidation struct {
	Kind      ValidationKind
	Required  bool
	Nullable  bool
	MinLength int
	MaxLength int
	Enum      []string
}

FieldValidation declares a strict, dependency-free input rule.

type FindManyQuery

type FindManyQuery struct {
	Model  string
	Where  []Where
	Limit  int
	Offset int
	Select []string
	Sort   *Sort
	Joins  []Join
}

type FindOneQuery

type FindOneQuery struct {
	Model  string
	Where  []Where
	Select []string
	Joins  []Join
}

type HookContext

type HookContext struct {
	Context         context.Context
	Request         *http.Request
	Path            string
	PluginID        string
	Params          map[string]string
	Headers         http.Header
	Query           url.Values
	Body            any
	RawBody         []byte
	Database        DatabaseAdapter
	Clock           Clock
	BaseURL         string
	Schema          Schema
	Cookies         CookieConfig
	Passwords       PasswordVerifier
	TrustedOrigins  []string
	SessionFreshAge time.Duration
	Session         *Session
	User            *User
	Response        *PluginResponse
	Failure         error
	GenerateID      func() (string, error)
	GenerateToken   func(int) (string, error)
	IsTrustedOrigin func(string) bool
	ValidateCSRF    func() error
	IssueSession    func(string) (*IssuedSession, error)
	// AuthenticateOAuth completes a plugin-owned, externally verified identity
	// transition through the core account/session store. Plugins must validate
	// issuer, audience, nonce, signature, and verified email before calling it.
	AuthenticateOAuth func(OAuthProfile, ProviderTokens) (*IssuedSession, bool, error)
	BackgroundTasks   BackgroundTaskRunner
	// contains filtered or unexported fields
}

HookContext is unique to one request.

func (*HookContext) RunInBackground

func (ctx *HookContext) RunInBackground(task BackgroundTask) error

type HookMatcher

type HookMatcher func(*HookContext) bool

HookMatcher selects requests using their normalized path and request-scoped context. A nil matcher selects every request.

type ImpersonationAuthorizer

type ImpersonationAuthorizer interface {
	CanImpersonate(context.Context, User, User) error
}

ImpersonationAuthorizer decides whether an authenticated actor may impersonate a subject. Returning an error denies the operation.

type IncrementQuery

type IncrementQuery struct {
	Model     string
	Where     []Where
	Increment map[string]float64
	Set       Record
}

type IndexSchema

type IndexSchema struct {
	Name   string
	Fields []string
	Unique bool
}

IndexSchema declares a compound adapter index using logical field names.

type InlineBackgroundTasks

type InlineBackgroundTasks struct{}

InlineBackgroundTasks runs submitted work synchronously with cancellation detached. Applications can replace it with a durable asynchronous runner.

func (InlineBackgroundTasks) Submit

type IssuedSession

type IssuedSession struct {
	Session Session `json:"session"`
	User    User    `json:"user"`
	// contains filtered or unexported fields
}

IssuedSession is the result of a plugin authentication transition. Bearer values remain private and can only be attached to a response through Apply.

func (*IssuedSession) Apply

func (issued *IssuedSession) Apply(response *PluginResponse) error

Apply attaches the secure session transition to a plugin response. It may be called once; a second call fails instead of duplicating bearer cookies.

type Join

type Join struct {
	Model    string
	From     string
	To       string
	Limit    int
	Relation JoinRelation
}

type JoinRelation

type JoinRelation string
const (
	JoinOneToOne   JoinRelation = "one-to-one"
	JoinOneToMany  JoinRelation = "one-to-many"
	JoinManyToMany JoinRelation = "many-to-many"
)

type Mail

type Mail struct {
	Kind      string
	To        string
	Token     string
	ActionURL string
	ExpiresAt time.Time
}

Mail contains a transactional authentication message. Implementations should render their own templates; Token and ActionURL are secrets and must not be logged.

type Mailer

type Mailer interface {
	Send(context.Context, Mail) error
}

Mailer delivers transactional authentication mail.

type ModelSchema

type ModelSchema struct {
	ModelName string
	Fields    map[string]FieldSchema
	Indexes   []IndexSchema
}

type NopRateLimiter

type NopRateLimiter struct{}

NopRateLimiter permits every request.

func (NopRateLimiter) Allow

type OAuthAccount

type OAuthAccount struct {
	ID                string    `json:"id"`
	UserID            string    `json:"userId"`
	Provider          string    `json:"providerId"`
	ProviderAccountID string    `json:"accountId"`
	Scope             string    `json:"scope,omitempty"`
	CreatedAt         time.Time `json:"createdAt"`
	UpdatedAt         time.Time `json:"updatedAt"`
}

OAuthAccount binds a provider identity to a user.

type OAuthProfile

type OAuthProfile struct {
	Provider          string
	ProviderAccountID string
	Email             string
	EmailVerified     bool
	Name              string
	ImageURL          string
}

OAuthProfile is the provider-neutral verified profile used for account creation and linking.

type OAuthProvider

type OAuthProvider interface {
	AuthorizationURL(state, codeChallenge, nonce, redirectURI string) (string, error)
	Exchange(context.Context, string, string, string, string) (OAuthResult, error)
}

OAuthProvider performs provider communication behind bounded contexts.

type OAuthProviderSignUpPolicy

type OAuthProviderSignUpPolicy interface {
	DisableImplicitSignUp() bool
	DisableSignUp() bool
}

OAuthProviderSignUpPolicy is an optional provider capability matching Better Auth v1.6's per-provider signup controls. Implementations that do not expose it retain the historical behavior of allowing implicit signup.

type OAuthResult

type OAuthResult struct {
	Profile OAuthProfile
	Tokens  ProviderTokens
}

type OAuthState

type OAuthState struct {
	ID              string
	Hash            string
	PKCEVerifier    string
	Nonce           string
	RedirectURI     string
	ReturnTo        string
	ErrorReturnTo   string
	NewUserReturnTo string
	LinkUserID      string
	RequestSignUp   bool
	ExpiresAt       time.Time
	CreatedAt       time.Time
}

OAuthState is a purpose-specific single-use authorization transaction.

type OAuthTokenRefresher

type OAuthTokenRefresher interface {
	Refresh(context.Context, string) (ProviderTokens, error)
}

OAuthTokenRefresher is implemented by providers that can exchange a refresh token for a new token set.

type OAuthUpsertPolicy

type OAuthUpsertPolicy struct {
	AllowImplicitLink        bool
	RequireLocalVerification bool
	UpdateUserInfoOnLink     bool
	UpdateAccountOnSignIn    bool
	AllowSignUp              bool
}

OAuthUpsertPolicy is the immutable store policy for an OAuth callback. It is evaluated inside the same transaction that creates or links the account.

type ObjectValidator

type ObjectValidator struct {
	Fields       map[string]FieldValidation
	AllowUnknown bool
}

ObjectValidator validates JSON objects and URL query values. Unknown fields are rejected unless AllowUnknown is explicitly enabled.

func (ObjectValidator) Validate

func (validator ObjectValidator) Validate(value any) error

func (ObjectValidator) ValidateConfiguration

func (validator ObjectValidator) ValidateConfiguration() error

ValidateConfiguration enables fail-closed validation during server construction.

type OneTimePurpose

type OneTimePurpose string

OneTimePurpose prevents token use across recovery flows.

type OneTimeToken

type OneTimeToken struct {
	ID        string
	UserID    string
	Hash      string
	Purpose   OneTimePurpose
	ExpiresAt time.Time
	CreatedAt time.Time
	Metadata  map[string]string
}

OneTimeToken is a hash-at-rest, expiring, single-use token record.

type OutboxDispatcher

type OutboxDispatcher struct {
	Database  DatabaseAdapter
	Handler   EventHandler
	Clock     Clock
	BatchSize int
}

func (OutboxDispatcher) RunOnce

func (dispatcher OutboxDispatcher) RunOnce(ctx context.Context) (int, error)

RunOnce delivers one ordered batch and marks successful records published. A handler error stops the batch and leaves that event unpublished.

type PasswordCredential

type PasswordCredential struct {
	UserID       string
	PasswordHash string
	UpdatedAt    time.Time
}

PasswordCredential contains a user's encoded password hash.

type PasswordVerification

type PasswordVerification struct {
	Valid           bool
	ReplacementHash string
}

type PasswordVerifier

type PasswordVerifier interface {
	Hash(context.Context, string) (string, error)
	Verify(context.Context, string, string) (PasswordVerification, error)
}

PasswordVerifier supports native formats and optional migration bridges.

type Plugin

type Plugin struct {
	ID             string
	Dependencies   []string
	Init           PluginInit
	Schema         Schema
	Endpoints      []PluginEndpoint
	Middlewares    []PluginMiddleware
	Before         []PluginBeforeHook
	After          []PluginAfterHook
	OnRequest      RequestHook
	OnResponse     ResponseHook
	TrustedOrigins []string
	RateLimits     []PluginRateLimitRule
	DatabaseHooks  []DatabaseHook
}

Plugin is an immutable descriptor compiled during New. Callbacks must be concurrency-safe and must not retain HookContext values.

type PluginAfterHook

type PluginAfterHook struct {
	Matcher HookMatcher
	Handler ResponseHook
}

PluginAfterHook runs after a matching endpoint has returned a response.

type PluginBeforeHook

type PluginBeforeHook struct {
	Matcher HookMatcher
	Handler RequestHook
}

PluginBeforeHook runs immediately before a matching endpoint.

type PluginEndpoint

type PluginEndpoint struct {
	Name            string
	Path            string
	Method          string
	SkipOriginCheck bool
	// AllowNonKebabPath permits protocol-mandated case-sensitive literals such
	// as SCIM's ServiceProviderConfig. Ordinary plugin routes should remain
	// lowercase kebab-case.
	AllowNonKebabPath bool
	Use               []RequestHook
	BodyValidator     EndpointValidator
	QueryValidator    EndpointValidator
	Handler           PluginEndpointHandler
}

PluginEndpoint declares a collision-checked HTTP route relative to the configured authentication base path. SkipOriginCheck is only for non-browser protocol callbacks or bearer-authenticated endpoints; enabling it does not skip endpoint middleware, validators, hooks, or rate limits.

type PluginEndpointHandler

type PluginEndpointHandler func(*HookContext) (*PluginResponse, error)

PluginEndpointHandler serves one plugin endpoint.

type PluginInit

type PluginInit func(PluginInitContext) (PluginInitResult, error)

PluginInit initializes a plugin once during New.

type PluginInitContext

type PluginInitContext struct {
	PluginID       string
	BaseURL        string
	Database       DatabaseAdapter
	Schema         Schema
	TrustedOrigins []string
}

PluginInitContext contains immutable construction-time capabilities.

type PluginInitResult

type PluginInitResult struct {
	Schema         Schema
	TrustedOrigins []string
}

PluginInitResult contains validated contributions produced at construction.

type PluginMiddleware

type PluginMiddleware struct {
	Matcher HookMatcher
	Handler RequestHook
}

PluginMiddleware runs before endpoint-specific middleware and before hooks.

type PluginRateLimitRule

type PluginRateLimitRule struct {
	Matcher    HookMatcher
	Action     string
	AccountKey func(*HookContext) string
	Window     time.Duration
	Max        int
}

PluginRateLimitRule adds a matcher-specific rule to the configured limiter.

type PluginResponse

type PluginResponse struct {
	Status  int
	Headers http.Header
	Body    []byte
}

func CSRFMiddleware

func CSRFMiddleware(context *HookContext) (*PluginResponse, error)

CSRFMiddleware enforces the configured double-submit CSRF token. Use it on state-changing plugin endpoints that authenticate with a session cookie. Trusted-origin enforcement still runs independently before plugin code.

func FreshSessionMiddleware

func FreshSessionMiddleware(context *HookContext) (*PluginResponse, error)

FreshSessionMiddleware requires a session created within the server's configured SessionFreshAge. Plugins should use it for credential enrollment and other sensitive account mutations.

func JSONResponse

func JSONResponse(status int, value any) (*PluginResponse, error)

JSONResponse creates a JSON plugin response.

func SessionMiddleware

func SessionMiddleware(context *HookContext) (*PluginResponse, error)

SessionMiddleware rejects requests without an active session. It can be used in PluginEndpoint.Use or as a plugin middleware handler.

func (*PluginResponse) DecodeJSON

func (response *PluginResponse) DecodeJSON(dst any) error

DecodeJSON decodes a plugin response body and rejects unknown fields.

func (*PluginResponse) SetCookie

func (response *PluginResponse) SetCookie(cookie *http.Cookie) error

SetCookie appends a secure, host-only cookie to a plugin response. Plugin cookies use the __Host- prefix so they cannot be scoped to a parent domain or a path outside the authentication server.

func (*PluginResponse) SetJSON

func (response *PluginResponse) SetJSON(value any) error

SetJSON replaces a plugin response body with encoded JSON.

type ProviderTokens

type ProviderTokens struct {
	AccessToken           string
	RefreshToken          string
	IDToken               string
	Scope                 string
	AccessTokenExpiresAt  time.Time
	RefreshTokenExpiresAt time.Time
}

type RateLimitDecision

type RateLimitDecision struct {
	Allowed    bool
	RetryAfter time.Duration
}

type RateLimitRequest

type RateLimitRequest struct {
	Action     string
	IP         string
	AccountKey string
	Window     time.Duration
	Max        int
}

RateLimitRequest is intentionally small so limiters can map it to local policies without receiving credentials.

type RateLimiter

type RateLimiter interface {
	Allow(context.Context, RateLimitRequest) (RateLimitDecision, error)
}

RateLimiter is called before expensive or abuse-sensitive work. Errors fail closed.

type Record

type Record map[string]any

Record is a schema-neutral database row. Adapter factories transform logical model and field names before a raw database adapter receives it.

type RequestHook

type RequestHook func(*HookContext) (*PluginResponse, error)

RequestHook runs before an endpoint. A non-nil response stops the remaining request pipeline and becomes the response.

func RequireResourceOwnership

func RequireResourceOwnership(config ResourceOwnershipConfig) (RequestHook, error)

RequireResourceOwnership returns middleware that requires a session and verifies a logical adapter record belongs to that user without disclosing whether a record with another owner exists.

type RequestMetadata

type RequestMetadata struct {
	RequestID string
	IP        string
	UserAgent string
}

RequestMetadata is safe, bounded request context for security audits.

type ResourceIDSource

type ResourceIDSource string

ResourceIDSource identifies where ownership middleware reads a resource ID.

const (
	ResourceIDParams ResourceIDSource = "params"
	ResourceIDQuery  ResourceIDSource = "query"
	ResourceIDBody   ResourceIDSource = "body"
)

Supported resource ID locations.

type ResourceOwnershipConfig

type ResourceOwnershipConfig struct {
	Model      string
	IDField    string
	IDParam    string
	IDSource   ResourceIDSource
	OwnerField string
}

ResourceOwnershipConfig configures RequireResourceOwnership.

type ResponseHook

type ResponseHook func(*HookContext, *PluginResponse) error

ResponseHook runs after an endpoint and may replace response fields.

type Schema

type Schema map[string]ModelSchema

func CoreSchema

func CoreSchema() Schema

CoreSchema returns an independent schema copy that plugins can extend before server construction.

func MergeSchema

func MergeSchema(base Schema, extensions ...Schema) (Schema, error)

type SchemaConfigurableAdapter

type SchemaConfigurableAdapter interface {
	WithSchema(Schema) (DatabaseAdapter, error)
}

SchemaConfigurableAdapter receives the fully merged logical schema before the server applies logical-to-physical query mapping. Adapters with a fixed schema do not need to implement it.

type Server

type Server struct {
	// contains filtered or unexported fields
}

func New

func New(cfg Config) (*Server, error)

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns an immutable, concurrency-safe standard library handler.

func (*Server) ResolveSession added in v1.0.1

func (s *Server) ResolveSession(ctx context.Context, r *http.Request) (SessionResult, error)

ResolveSession resolves the configured session cookie without invoking the HTTP handler or JSON serialization. Missing, invalid, expired, or revoked sessions and disabled users return ErrNoSession. Persistence and context failures are returned distinctly.

ResolveSession is safe for concurrent use. It does not mutate the request, rotate the session, refresh cookies, or return the opaque session token.

func (*Server) Schema

func (s *Server) Schema() Schema

Schema returns an independent copy of the fully merged core, application, and plugin schema. Schema-aware adapters use it for explicit migrations.

func (*Server) SetPassword

func (s *Server) SetPassword(ctx context.Context, userID, password string) error

SetPassword sets or replaces the credential password for a user. It is a trusted server API and is deliberately not exposed as an HTTP endpoint.

func (*Server) VerifyPassword

func (s *Server) VerifyPassword(ctx context.Context, userID, password string) (bool, error)

VerifyPassword verifies a credential without creating a session.

type ServerHooks

type ServerHooks struct {
	OnRequest  RequestHook
	Before     []PluginBeforeHook
	After      []PluginAfterHook
	OnResponse ResponseHook
}

ServerHooks configures application-owned lifecycle hooks outside a plugin.

type Session

type Session struct {
	ID              string     `json:"id"`
	UserID          string     `json:"userId"`
	TokenHash       string     `json:"-"`
	ExpiresAt       time.Time  `json:"expiresAt"`
	CreatedAt       time.Time  `json:"createdAt"`
	UpdatedAt       time.Time  `json:"updatedAt"`
	LastSeenAt      time.Time  `json:"lastSeenAt"`
	RevokedAt       *time.Time `json:"-"`
	ImpersonatorID  string     `json:"impersonatedBy,omitempty"`
	ImpersonationID string     `json:"impersonationId,omitempty"`
}

Session is a server-side session. TokenHash is never serialized to clients.

type SessionResult added in v1.0.1

type SessionResult struct {
	Session Session `json:"session"`
	User    User    `json:"user"`
}

SessionResult is an authenticated session and its owning user as resolved from an incoming request.

type Sort

type Sort struct {
	Field     string
	Direction string
}

type StoredOAuthAccount

type StoredOAuthAccount struct {
	Account OAuthAccount
	Tokens  ProviderTokens
}

type StringMode

type StringMode string
const (
	StringSensitive   StringMode = "sensitive"
	StringInsensitive StringMode = "insensitive"
)

type SyntheticUserFactory

type SyntheticUserFactory func(SyntheticUserInput) Record

SyntheticUserFactory builds an enumeration-resistant duplicate-signup user shape, including application fields needed to match a real signup response.

type SyntheticUserInput

type SyntheticUserInput struct {
	CoreFields       Record
	AdditionalFields Record
	ID               string
}

SyntheticUserInput contains only public signup fields. AdditionalFields is reserved for application-declared user schema fields and is an independent map that a factory may safely retain or mutate.

type TokenCipher

type TokenCipher interface {
	Seal(context.Context, string) (string, error)
	Open(context.Context, string) (string, error)
}

TokenCipher encrypts provider credentials before persistence.

type TokenSource

type TokenSource interface {
	Token(byteLength int) (string, error)
}

TokenSource creates cryptographically unpredictable URL-safe opaque values.

type TrustedOriginResolver

type TrustedOriginResolver interface {
	TrustedOrigins(context.Context, *http.Request) ([]string, error)
}

TrustedOriginResolver returns additional Better Auth v1.6 trusted-origin policies for one request. Results are bounded, validated, and never retained on the shared server. Implementations must be concurrency-safe.

type TrustedOriginResolverFunc

type TrustedOriginResolverFunc func(context.Context, *http.Request) ([]string, error)

TrustedOriginResolverFunc adapts a function to TrustedOriginResolver.

func (TrustedOriginResolverFunc) TrustedOrigins

func (resolver TrustedOriginResolverFunc) TrustedOrigins(
	ctx context.Context,
	request *http.Request,
) ([]string, error)

type TrustedProviderResolver

type TrustedProviderResolver interface {
	TrustedProviders(context.Context, *http.Request) ([]string, error)
}

TrustedProviderResolver resolves Better Auth v1.6's request-dependent trustedProviders option without retaining request state on the server.

type TrustedProviderResolverFunc

type TrustedProviderResolverFunc func(context.Context, *http.Request) ([]string, error)

TrustedProviderResolverFunc adapts a function to TrustedProviderResolver.

func (TrustedProviderResolverFunc) TrustedProviders

func (resolver TrustedProviderResolverFunc) TrustedProviders(
	ctx context.Context,
	request *http.Request,
) ([]string, error)

type UpdateQuery

type UpdateQuery struct {
	Model  string
	Where  []Where
	Update Record
}

type User

type User struct {
	ID            string     `json:"id"`
	Email         string     `json:"email"`
	Name          string     `json:"name,omitempty"`
	ImageURL      string     `json:"image,omitempty"`
	EmailVerified bool       `json:"emailVerified"`
	CreatedAt     time.Time  `json:"createdAt"`
	UpdatedAt     time.Time  `json:"updatedAt"`
	DisabledAt    *time.Time `json:"-"`
}

User is the adapter-independent authenticated identity.

func (User) MarshalJSON

func (user User) MarshalJSON() ([]byte, error)

MarshalJSON preserves the native Go string field while matching Better Auth's nullable public image field.

type UserDeletionHook

type UserDeletionHook func(context.Context, User) error

UserDeletionHook runs application cleanup or policy immediately before or after durable account deletion. Implementations must be concurrency-safe.

type UserLifecycleHook

type UserLifecycleHook func(context.Context, User) error

UserLifecycleHook observes a Better Auth lifecycle transition. Implementations must be concurrency-safe.

type UserManagementConfig

type UserManagementConfig struct {
	ChangeEmailEnabled             bool
	SendChangeEmailConfirmation    bool
	UpdateEmailWithoutVerification bool
	DeleteUserEnabled              bool
	SendDeleteAccountVerification  bool
	BeforeDelete                   UserDeletionHook
	AfterDelete                    UserDeletionHook
}

type ValidationKind

type ValidationKind string

ValidationKind is the JSON/query value type required by a FieldValidation.

const (
	ValidationString  ValidationKind = "string"
	ValidationNumber  ValidationKind = "number"
	ValidationInteger ValidationKind = "integer"
	ValidationBoolean ValidationKind = "boolean"
	ValidationObject  ValidationKind = "object"
	ValidationArray   ValidationKind = "array"
)

type Where

type Where struct {
	Field     string
	Operator  WhereOperator
	Value     any
	Connector WhereConnector
	Mode      StringMode
}

func Eq

func Eq(field string, value any) Where

func ValidateWhere

func ValidateWhere(where []Where, allowEmpty bool) ([]Where, error)

ValidateWhere applies contract defaults and rejects malformed predicates.

type WhereConnector

type WhereConnector string
const (
	WhereAND WhereConnector = "AND"
	WhereOR  WhereConnector = "OR"
)

type WhereOperator

type WhereOperator string
const (
	WhereEQ         WhereOperator = "eq"
	WhereNE         WhereOperator = "ne"
	WhereLT         WhereOperator = "lt"
	WhereLTE        WhereOperator = "lte"
	WhereGT         WhereOperator = "gt"
	WhereGTE        WhereOperator = "gte"
	WhereIn         WhereOperator = "in"
	WhereNotIn      WhereOperator = "not_in"
	WhereContains   WhereOperator = "contains"
	WhereStartsWith WhereOperator = "starts_with"
	WhereEndsWith   WhereOperator = "ends_with"
)

Directories

Path Synopsis
adapter
memory
Package memory provides a concurrency-safe adapter for tests, examples, and ephemeral development.
Package memory provides a concurrency-safe adapter for tests, examples, and ephemeral development.
mongodb
Package mongodb implements the generic Better Auth database adapter contract.
Package mongodb implements the generic Better Auth database adapter contract.
postgresql
Package postgresql provides the Better Auth PostgreSQL database adapter.
Package postgresql provides the Better Auth PostgreSQL database adapter.
sqladapter
Package sqladapter implements the shared database/sql adapter used by the PostgreSQL and SQLite dialect packages.
Package sqladapter implements the shared database/sql adapter used by the PostgreSQL and SQLite dialect packages.
sqlite
Package sqlite provides the Better Auth SQLite database adapter.
Package sqlite provides the Better Auth SQLite database adapter.
Package adaptertest publishes the conformance suite used by first-party and third-party database adapters.
Package adaptertest publishes the conformance suite used by first-party and third-party database adapters.
examples
installcheck command
nethttp command
plugin
organization
Package organization provides Better Auth-shaped multi-tenant organization management and authorization.
Package organization provides Better Auth-shaped multi-tenant organization management and authorization.
passkey
Package passkey provides an opt-in Better Auth-shaped WebAuthn plugin.
Package passkey provides an opt-in Better Auth-shaped WebAuthn plugin.
scim
Package scim provides an inbound Better Auth-shaped SCIM 2.0 provisioning service.
Package scim provides an inbound Better Auth-shaped SCIM 2.0 provisioning service.
sso
Package sso provides Better Auth-shaped OIDC, OAuth 2.0, and SAML enterprise single sign-on.
Package sso provides Better Auth-shaped OIDC, OAuth 2.0, and SAML enterprise single sign-on.
twofactor
Package twofactor provides an opt-in Better Auth-shaped two-factor plugin.
Package twofactor provides an opt-in Better Auth-shaped two-factor plugin.
Package social provides Better Auth-compatible built-in OAuth2/OIDC provider presets and a generic provider constructor.
Package social provides Better Auth-compatible built-in OAuth2/OIDC provider presets and a generic provider constructor.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL