gobetterauth

package module
v2.4.0 Latest Latest
Warning

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

Go to latest
Published: Jan 31, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

README

Project Logo


Table of Contents

  1. Introduction
  2. Features
  3. Docs
  4. Contributing

Introduction

✨ Overview

GoBetterAuth is an open-source authentication solution that scales with you. Embed it as a library in your Go app, or run it as a standalone auth server with any tech stack. All functionality is delivered through a powerful plugin system, allowing you to compose exactly the authentication stack you need — no more, no less, all built with clean architecture. GoBetterAuth is flexible enough to integrate with any technology stack. It streamlines the implementation of essential security features through a clean, modular architecture, allowing developers to concentrate on building their applications without the overhead of managing authentication complexities.


🎯 Who is it for?

GoBetterAuth is ideal for:

  • Startups that want full control over their authentication stack
  • Teams building microservices or multi-backend systems
  • Companies with self-hosting or compliance requirements
  • Go developers who want first-class embedded auth
  • Anyone who wants modern auth without SaaS lock-in

🧩 Plugins & Capabilities

GoBetterAuth is architected around a powerful plugin and capability system.

Plugins are modular packages that encapsulate related authentication features.
Capabilities represent individual, fine-grained functionalities exposed by these plugins.

Each plugin can offer multiple capabilities, and every route in your application explicitly declares which capabilities it leverages. This approach ensures that authentication logic is:

  • Explicit – No hidden behaviors; every capability is clearly declared.
  • Composable – Mix and match only the features you need.
  • Auditable – Easily track which routes use which authentication features.
  • Understandable – The authentication flow is transparent and easy to reason about.

This design empowers you to build secure, maintainable, and highly customizable authentication flows tailored to your application's needs.


Features via Plugins

  • 📧 Email & Password: Authentication, Email Verification & Password Reset
  • 🌐 OAuth providers
  • 💾 Multiple database backends
  • 🗄️ Secondary storage (Redis, memory, DB)
  • ⚡ Rate limiting
  • 🛡️ CSRF protection
  • 🪝 Hooks system
  • 📨 Event bus
  • 🧩 Custom routes and logic

🪝 Hooks System

GoBetterAuth includes a powerful, lifecycle-based hooks system that lets you intercept and customize request handling at every stage of the HTTP pipeline.

Hooks allow you to implement:

  • custom authentication logic
  • request validation
  • logging & tracing
  • metrics
  • access control
  • A/B testing
  • feature flags
  • audit trails
  • custom headers
  • dynamic routing

All without modifying core code.

Build your own plugins for:

  • business logic
  • custom routes
  • custom auth flows
  • external integrations
  • internal tooling

⚙️ Deployment Modes

Embedded Mode (Go Library)

Embed GoBetterAuth directly into your Go application:

import (
  gobetterauth "github.com/GoBetterAuth/go-better-auth"
  gobetterauthconfig "github.com/GoBetterAuth/go-better-auth/config"
  gobetterauthmodels "github.com/GoBetterAuth/go-better-auth/models"
)

config := gobetterauthconfig.NewConfig(
  gobetterauthconfig.WithAppName("GoBetterAuthPlayground"),
  gobetterauthconfig.WithBasePath("/api/auth"),
  gobetterauthconfig.WithDatabase(gobetterauthmodels.DatabaseConfig{
    Provider: "postgres",
    URL:      os.Getenv(gobetterauthenv.EnvDatabaseURL),
  }),
  // other config options...
)

auth := gobetterauth.New(gobetterauth.AuthConfig{
  Config:  config,
  Plugins: []gobetterauthmodels.Plugin{
    emailpasswordplugin.New(...),
    // other plugins...
  },
})

http.ListenAndServe(":8080", auth.Handler())

You get:

  • zero network overhead
  • full type safety
  • native integration
  • maximum performance

Server Mode (Standalone Auth Server)

Run GoBetterAuth as a standalone authentication server via Docker:

docker run -itd -p 8080:8080 \
  -v $(pwd)/config.toml:/home/appuser/config.toml \
  -e GO_BETTER_AUTH_ADMIN_API_KEY=my-admin-api-key \
  -e GO_BETTER_AUTH_BASE_URL=http://localhost:8080 \
  -e GO_BETTER_AUTH_SECRET=my-app-secret \
  -e GO_BETTER_AUTH_DATABASE_URL=<your_connection_string> \
  # other env vars depending on plugins used...
  ghcr.io/gobetterauth/go-better-auth:latest

Use it from any language or framework over HTTP.

Perfect for:

  • microservices
  • polyglot stacks

🧠 Design Principles

  • Plugin-first architecture
  • Clean architecture
  • Minimal dependencies
  • Standard library first
  • Secure by default
  • Framework agnostic
  • Self-hosted
  • Extensible

🚀 Roadmap

  • Many more plugins including Admin, Organizations, RBAC, MFA...
  • And more to be announced!

📜 License

Apache 2.0 License


Docs

For more info and a full guide on how to use this library, check out the Docs.


Contributing

Your contributions are welcome! Here's how you can get involved:


Support & Community

Join our growing community for support, discussions, and updates:


Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DropCoreMigrations

func DropCoreMigrations(ctx context.Context, logger models.Logger, dbProvider string, db bun.IDB) error

func InitCoreServices

func InitCoreServices(config *models.Config, db bun.IDB, serviceRegistry models.ServiceRegistry) *coreservices.CoreServices

func InitDatabase

func InitDatabase(config *models.Config, logger models.Logger, logLevel string) (bun.IDB, error)

InitDatabase creates a Bun DB connection based on provider

func InitEventBus

func InitEventBus(config *models.Config) (models.EventBus, error)

InitEventBus creates an event bus based on the configuration

func InitLogger

func InitLogger(config *models.Config) models.Logger

InitLogger initializes the logger based on configuration

func RunCoreMigrations

func RunCoreMigrations(ctx context.Context, logger models.Logger, dbProvider string, db bun.IDB) error

Types

type Auth

type Auth struct {
	ServiceRegistry models.ServiceRegistry
	PluginRegistry  models.PluginRegistry

	Api internal.CoreAPI
	// contains filtered or unexported fields
}

Auth is a composition root and entry point for the authentication framework.

func New

func New(authConfig *AuthConfig) *Auth

New creates a new Auth instance using the provided config and plugins. Handles plugin registration, migrations, and initialization in unified way. Works identically whether plugins are manually instantiated or built from config.

func (*Auth) ClosePlugins

func (auth *Auth) ClosePlugins() error

ClosePlugins calls Close for all registered plugins

func (*Auth) DropCoreMigrations

func (auth *Auth) DropCoreMigrations(ctx context.Context) error

func (*Auth) GetAccountService

func (auth *Auth) GetAccountService() services.AccountService

func (*Auth) GetJWTService

func (auth *Auth) GetJWTService() services.JWTService

func (*Auth) GetMailerService

func (auth *Auth) GetMailerService() services.MailerService

func (*Auth) GetPasswordService

func (auth *Auth) GetPasswordService() services.PasswordService

func (*Auth) GetSessionService

func (auth *Auth) GetSessionService() services.SessionService

func (*Auth) GetTokenService

func (auth *Auth) GetTokenService() services.TokenService

func (*Auth) GetUserIDFromContext

func (auth *Auth) GetUserIDFromContext(ctx context.Context) (string, bool)

GetUserIDFromContext retrieves the user ID from a context. Returns the user ID and a boolean indicating whether it was found. This is a convenience wrapper around models.GetUserIDFromContext to avoid requiring application code to import the models package.

func (*Auth) GetUserIDFromRequest

func (auth *Auth) GetUserIDFromRequest(req *http.Request) (string, bool)

GetUserIDFromRequest retrieves the user ID from an HTTP request's context. Returns the user ID and a boolean indicating whether it was found. This is a convenience wrapper around models.GetUserIDFromRequest to avoid requiring application code to import the models package.

func (*Auth) GetUserService

func (auth *Auth) GetUserService() services.UserService

func (*Auth) GetVerificationService

func (auth *Auth) GetVerificationService() services.VerificationService

func (*Auth) Handler

func (auth *Auth) Handler() http.Handler

Handler returns the HTTP handler that serves all authentication routes and hooks. It registers routes and hooks from all plugins with the router. This is the entry point for HTTP traffic.

func (*Auth) RegisterCustomRoute

func (auth *Auth) RegisterCustomRoute(route models.Route)

RegisterCustomRoute registers a single custom route without the basePath prefix This is useful for application routes that should not be under the auth basePath

func (*Auth) RegisterCustomRoutes

func (auth *Auth) RegisterCustomRoutes(routes []models.Route)

RegisterCustomRoutes registers multiple custom routes without the basePath prefix This is useful for application routes that should not be under the auth basePath

func (*Auth) RegisterHook

func (auth *Auth) RegisterHook(hook models.Hook)

RegisterHook registers a single hook to the router. Hooks allow developers to intercept and modify requests/responses at various stages of the request lifecycle (OnRequest, Before, After, OnResponse).

func (*Auth) RegisterHooks

func (auth *Auth) RegisterHooks(hooks []models.Hook)

RegisterHooks registers multiple hooks to the router. Hooks allow developers to intercept and modify requests/responses at various stages of the request lifecycle (OnRequest, Before, After, OnResponse).

func (*Auth) RegisterMiddleware

func (auth *Auth) RegisterMiddleware(middleware ...func(http.Handler) http.Handler)

RegisterMiddleware registers middleware to the chi router. Middleware should be registered before calling Handler().

func (*Auth) RegisterRoute

func (auth *Auth) RegisterRoute(route models.Route)

RegisterRoute registers a single route with the basePath prefix

func (*Auth) RegisterRoutes

func (auth *Auth) RegisterRoutes(routes []models.Route)

RegisterRoutes registers multiple routes with the basePath prefix

func (*Auth) RunCoreMigrations

func (auth *Auth) RunCoreMigrations(ctx context.Context) error

type AuthConfig

type AuthConfig struct {
	Config  *models.Config
	Plugins []models.Plugin
}

type HookErrorMode

type HookErrorMode string

HookErrorMode defines how the router handles errors from hook handlers

const (
	// HookErrorModeContinue logs errors but continues to next hook (default)
	HookErrorModeContinue HookErrorMode = "error-log-continue"
	// HookErrorModeFailFast logs error and sets ctx.Handled=true to skip remaining hooks in current stage
	HookErrorModeFailFast HookErrorMode = "error-log-fail-fast"
	// HookErrorModeSilent silently ignores errors without logging
	HookErrorModeSilent HookErrorMode = "error-silent"
)

type HookType

type HookType string

HookErrorMode defines how the router handles errors from hook handlers

const (
	// HookTypeSync indicates a synchronous hook that runs in the main request flow
	HookTypeSync HookType = "sync"
	// HookTypeAsync indicates an asynchronous hook that runs in a background goroutine
	HookTypeAsync HookType = "async"
)

type Router

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

Router wraps chi.Router and manages hooks for the request lifecycle

func NewRouter

func NewRouter(config *models.Config, logger models.Logger, opts *RouterOptions) *Router

NewRouter creates a new Router with Chi as the underlying router opts can be nil to use default options

func (*Router) Get

func (r *Router) Get() chi.Router

Get returns the underlying chi.Router for direct access

func (*Router) Handler

func (r *Router) Handler() http.Handler

Handler returns the configured HTTP handler - the Router with hook middleware

func (*Router) RegisterCustomRoute

func (r *Router) RegisterCustomRoute(route models.Route)

RegisterCustomRoute registers a custom route without the basePath prefix This is useful for application routes that should not be under the auth basePath

func (*Router) RegisterCustomRoutes

func (r *Router) RegisterCustomRoutes(routes []models.Route)

RegisterCustomRoutes registers multiple custom routes without the basePath prefix This is useful for application routes that should not be under the auth basePath

func (*Router) RegisterHook

func (r *Router) RegisterHook(hook models.Hook)

RegisterHook registers a single hook

func (*Router) RegisterHooks

func (r *Router) RegisterHooks(hooks []models.Hook)

RegisterHooks registers multiple hooks

func (*Router) RegisterMiddleware

func (r *Router) RegisterMiddleware(middleware ...func(http.Handler) http.Handler)

RegisterMiddleware registers global middleware with Chi

func (*Router) RegisterRoute

func (r *Router) RegisterRoute(route models.Route)

RegisterRoute registers a single route with Chi

func (*Router) RegisterRoutes

func (r *Router) RegisterRoutes(routes []models.Route)

RegisterRoutes registers multiple routes with an optional base path

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP implements http.Handler for testing and direct use

func (*Router) SetRouteMetadataFromConfig

func (r *Router) SetRouteMetadataFromConfig(routeMetadata map[string]map[string]any)

SetRouteMetadataFromConfig sets route metadata mappings from RouteMappings. This populates the internal metadata map used to assign ctx.Route.Metadata["plugins"] during request handling. Supports both static and dynamic (parameterized) routes. Format: routeMetadata["METHOD:path"] = {"plugins": ["plugin1", "plugin2"], ...} Examples:

  • Static route: "GET:/me" -> plugins for GET /me
  • Dynamic route: "POST:/oauth2/callback/{provider}" -> plugins for POST /oauth2/callback/{provider} (matches any provider value)
  • Multi-param: "GET:/users/{id}/posts/{postId}" -> plugins for any GET request with that pattern

Dynamic routes use {paramName} syntax and match any actual parameter value at that position. At request time, the router first tries exact path matching, then falls back to pattern matching.

type RouterOptions

type RouterOptions struct {
	// AsyncHookTimeout is the timeout for async hook execution (default: 30 seconds)
	// If a hook takes longer than this, it will be cancelled
	AsyncHookTimeout time.Duration
	// HookErrorMode defines how errors from hooks are handled (default: HookErrorModeContinue)
	// Controls whether errors cause early exit, silent ignoring, or just logging
	HookErrorMode HookErrorMode
}

RouterOptions contains configuration options for the Router

func DefaultRouterOptions

func DefaultRouterOptions() *RouterOptions

DefaultRouterOptions returns router options with sensible defaults

Jump to

Keyboard shortcuts

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