auth

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 31 Imported by: 0

README

awesome-go-auth

awesome-go-auth is a Go authentication library with stateful sessions and access/refresh tokens.

Installation

go get github.com/nik2208/awesome-go-auth

Quick start

package main

import (
	"context"
	"log"

	auth "github.com/nik2208/awesome-go-auth"
)

func main() {
	cfg := auth.DefaultConfig("replace-with-at-least-32-random-chars")
	service, err := auth.NewService(cfg, auth.NewMemoryUserStore(), auth.NewMemorySessionStore())
	if err != nil {
		log.Fatal(err)
	}

	_, tokens, err := service.Register(context.Background(), auth.RegisterInput{
		Email:    "alice@example.com",
		Password: "supersecurepassword",
		TenantID: "tenant-1",
	})
	if err != nil {
		log.Fatal(err)
	}

	log.Println("access token issued", tokens.AccessToken != "")
}

Features

  • Secure configuration with validation.
  • Register/login with password hashing (bcrypt).
  • Signed access token + refresh token (HMAC-SHA256) with expiry.
  • Stateful sessions with refresh token rotation and revocation (logout).
  • Configurable session check policy (allcalls / refresh / none).
  • Authenticated user retrieval (Me).
  • Account management (UpdateProfile, DeleteAccount) in addition to password/email lifecycle.
  • CSRF double-submit middleware (cookie + header) for browser flows.
  • Password reset (ForgotPassword, ResetPassword, ChangePassword).
  • Passwordless magic link (SendMagicLink, VerifyMagicLink).
  • SMS OTP login (SendSMSCode, VerifySMSCode).
  • TOTP 2FA (SetupTOTP, VerifyTOTPSetup, VerifyTOTP, DisableTOTP).
  • Email verification (SendVerificationEmailToken, VerifyEmail) and email change (RequestEmailChange, ConfirmEmailChange).
  • Session admin helpers (ListSessions, RevokeSessionByID, CleanupExpiredSessions).
  • User metadata store and service helpers.
  • Multi-tenant in-memory RBAC (MemoryRolesPermissionsStore) with roles and permissions.
  • In-memory tenant store (MemoryTenantStore) with user↔tenant membership.
  • Custom token claims via Config.BuildTokenClaims, also reflected in the enriched profile.
  • API key service and HTTP middleware (APIKeyService, APIKeyMiddleware).
  • In-process event bus (EventBus) for event-driven integrations.
  • Extended storage interfaces and thread-safe in-memory implementations for all the above flows.

Idiomatic entrypoint and HTTP adapters

  • auth.New(...) entrypoint with functional options (WithSecret, WithTokenTTLs, WithUserStore, WithSessionStore, etc.).
  • Framework-agnostic adapters available:
    • adapter/nethttp (Middleware, Mount)
    • adapter/chi (Middleware, Mount)
    • adapter/gin (Middleware, Mount)
    • adapter/echo (Middleware, Mount)

Parity Snapshot vs awesome-node-auth

Capability Status in awesome-go-auth Notes
Auth strategies (email/password, magic link, SMS OTP, TOTP 2FA, OAuth linking) ✅ Implemented OAuth + account linking in oauth.go.
Token management (cookie/bearer, access/refresh rotation, secure cookies) ✅ Implemented Adapter HTTP supportano cookie e bearer; rotation attiva.
Identity Provider (IdP) mode (RS256 + JWKS + resource server validation) ✅ Implemented OIDC IdP con discovery, authorize, token, userinfo e JWKS.
Stateful sessions ✅ Implemented Revoca/rotation + Config.SessionCheckOn (allcalls/refresh/none).
Dynamic email templates + UI i18n fallback ✅ Implemented Template mail + fallback i18n built-in.
CSRF protection ✅ Implemented CSRFMiddleware cookie+header double-submit.
Account management ✅ Implemented Register, UpdateProfile, DeleteAccount, password/email lifecycle.
Account linking ✅ Implemented Pending link + linked account store.
RBAC ✅ Implemented RolesPermissionsStore tenant-aware.
Multi-tenancy ✅ Implemented TenantStore e membership utente↔tenant.
Admin panel ✅ Implemented ServeAdminUI() embedded.
Built-in UI + auth runtime (auth.js) ✅ Implemented ServeAuthUI() + ServeAuthJS().
Client libraries compatibility (Angular + Flutter) ✅ Implemented Cookie+CSRF browser e bearer per native client.
Event-driven tooling (event bus, SSE, inbound/outbound webhooks, telemetry, notify channels) ✅ Implemented Event bus, SSE, webhooks, telemetry, notify.
API keys (M2M) ✅ Implemented APIKeyService + middleware API key.
OpenAPI / Swagger docs ✅ Implemented GenerateOpenAPISpec.
MCP server (awesome-node-auth-mcp-server) ➖ Out of scope Fuori scope di parity per questa libreria.

Documentation

Index

Constants

View Source
const (
	SessionCheckOnAllCalls = "allcalls"
	SessionCheckOnRefresh  = "refresh"
	SessionCheckOnNone     = "none"
)
View Source
const (
	EmailVerificationModeNone   = "none"
	EmailVerificationModeLazy   = "lazy"
	EmailVerificationModeStrict = "strict"
)

Email verification modes accepted by Config.EmailVerificationMode.

none   : Register marks the address verified, so verification never comes up
         on the self-registration path. An address left unverified by some
         other route (admin provisioning, a data import, a custom UserStore
         whose column defaults to false) is still refused at login. This is
         the default and is exactly how the service behaved before the mode
         existed.
lazy   : Register leaves the address unverified and login is allowed anyway.
         This is the only mode in which an unverified address may log in.
strict : Register leaves the address unverified and login is refused until
         the address is confirmed.

Variables

View Source
var (
	ErrInvalidCredentials  = errors.New("auth: invalid credentials")
	ErrUserExists          = errors.New("auth: user already exists")
	ErrInvalidToken        = errors.New("auth: invalid token")
	ErrSessionNotFound     = errors.New("auth: session not found")
	ErrSessionRevoked      = errors.New("auth: session revoked")
	ErrWeakPassword        = errors.New("auth: password is too weak")
	ErrFeatureNotSupported = errors.New("auth: feature not supported by configured stores")
	ErrEmailNotVerified    = errors.New("auth: email not verified")
	ErrInvalidCode         = errors.New("auth: invalid code")
	ErrTwoFactorRequired   = errors.New("auth: two-factor authentication required")
	ErrAlreadyExists       = errors.New("auth: resource already exists")
	ErrTenantNotFound      = errors.New("auth: tenant not found")
	ErrRoleNotFound        = errors.New("auth: role not found")
)

Functions

func APIKeyMiddleware

func APIKeyMiddleware(store APIKeyStore, requiredScopes []string) func(http.Handler) http.Handler

func CSRFMiddleware

func CSRFMiddleware(cfg CSRFConfig) func(http.Handler) http.Handler

CSRFMiddleware validates mutating browser requests using the double-submit pattern.

func GenerateOpenAPISpec

func GenerateOpenAPISpec(info OpenAPIInfo) map[string]any

GenerateOpenAPISpec returns an OpenAPI 3.0 spec for awesome-go-auth endpoints.

func ServeAdminUI

func ServeAdminUI() http.Handler

ServeAdminUI returns an http.Handler serving the embedded admin dashboard HTML.

func ServeAuthJS

func ServeAuthJS() http.Handler

ServeAuthJS returns an http.Handler serving the embedded auth.js browser SDK.

func ServeAuthUI

func ServeAuthUI() http.Handler

ServeAuthUI returns an http.Handler serving the embedded auth UI HTML (login/register).

func ServeSSE

func ServeSSE(hub *SseHub, channel string) http.HandlerFunc

ServeSSE is an http.HandlerFunc that streams SSE to a connected client. channel is typically the authenticated user's ID.

func VerifyWebhookSignature

func VerifyWebhookSignature(secret string, body []byte, sigHeader string) error

VerifyWebhookSignature validates an inbound webhook signature.

Types

type APIKeyRecord

type APIKeyRecord struct {
	ID         string
	Prefix     string
	Name       string
	ServiceID  string
	KeyHash    string
	Scopes     []string
	AllowedIPs []string
	IsActive   bool
	ExpiresAt  *time.Time
	LastUsedAt *time.Time
}

APIKeyRecord stores hashed key material and policy constraints.

type APIKeyService

type APIKeyService struct{}

func NewAPIKeyService

func NewAPIKeyService() *APIKeyService

func (*APIKeyService) Create

func (s *APIKeyService) Create(ctx context.Context, store APIKeyStore, name, serviceID string, scopes, allowedIPs []string, expiresAt *time.Time) (rawKey string, record APIKeyRecord, err error)

func (*APIKeyService) Verify

func (s *APIKeyService) Verify(ctx context.Context, store APIKeyStore, rawKey string, ip string, requiredScopes []string) (APIKeyRecord, error)

type APIKeyStore

type APIKeyStore interface {
	Save(ctx context.Context, key APIKeyRecord) error
	FindByPrefix(ctx context.Context, prefix string) (APIKeyRecord, error)
	Revoke(ctx context.Context, id string) error
	UpdateLastUsed(ctx context.Context, id string, when time.Time) error
}

APIKeyStore persists and resolves API keys.

type Auth

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

Auth is the top-level entrypoint configured with functional options.

func New

func New(opts ...Option) (*Auth, error)

New creates a configured Auth instance.

func (*Auth) DeleteAccount

func (a *Auth) DeleteAccount(ctx context.Context, in DeleteAccountInput) error

DeleteAccount delegates to Service.DeleteAccount.

func (*Auth) Login

func (a *Auth) Login(ctx context.Context, in LoginInput) (User, AuthTokens, error)

Login delegates to Service.Login.

func (*Auth) Logout

func (a *Auth) Logout(ctx context.Context, refreshToken string) error

Logout delegates to Service.Logout.

func (*Auth) Me

func (a *Auth) Me(ctx context.Context, accessToken string) (User, error)

Me delegates to Service.Me.

func (*Auth) Refresh

func (a *Auth) Refresh(ctx context.Context, refreshToken string) (AuthTokens, error)

Refresh delegates to Service.Refresh.

func (*Auth) Register

func (a *Auth) Register(ctx context.Context, in RegisterInput) (User, AuthTokens, error)

Register delegates to Service.Register.

func (*Auth) Service

func (a *Auth) Service() *Service

Service exposes the configured core service.

func (*Auth) UpdateProfile

func (a *Auth) UpdateProfile(ctx context.Context, in UpdateProfileInput) (User, error)

UpdateProfile delegates to Service.UpdateProfile.

type AuthTokens

type AuthTokens struct {
	AccessToken  string
	RefreshToken string
	ExpiresIn    time.Duration
}

AuthTokens are the issued access/refresh pair.

type CSRFConfig

type CSRFConfig struct {
	APIPrefix      string
	CookieName     string
	HeaderName     string
	CookieSecure   bool
	CookieSameSite http.SameSite
}

CSRFConfig configures cookie+header double-submit CSRF protection.

func DefaultCSRFConfig

func DefaultCSRFConfig(apiPrefix string) CSRFConfig

DefaultCSRFConfig returns defaults compatible with browser cookie auth flows.

type ChangeEmailRequestInput

type ChangeEmailRequestInput struct {
	UserID   string
	TenantID string
	NewEmail string
}

type ChangePasswordInput

type ChangePasswordInput struct {
	UserID          string
	TenantID        string
	CurrentPassword string
	NewPassword     string
}

type Config

type Config struct {
	Secret                string
	Issuer                string
	AccessTokenTTL        time.Duration
	RefreshTokenTTL       time.Duration
	SessionCheckOn        string
	ClockSkew             time.Duration
	MinPasswordLen        int
	ResetTokenTTL         time.Duration
	MagicLinkTTL          time.Duration
	SMSCodeTTL            time.Duration
	EmailVerificationTTL  time.Duration
	EmailVerificationMode string
	EmailChangeTTL        time.Duration
	TempTokenTTL          time.Duration
	Require2FA            bool
	BuildTokenClaims      func(ctx context.Context, user User) (map[string]any, error)
	Logger                func(format string, args ...any)
}

Config contains security and token settings for the auth service.

func DefaultConfig

func DefaultConfig(secret string) Config

DefaultConfig returns secure defaults for development and production bootstrap.

type ConfirmEmailChangeInput

type ConfirmEmailChangeInput struct {
	Token string
}

type DeleteAccountInput

type DeleteAccountInput struct {
	UserID   string
	TenantID string
}

type EmailChangeStore

type EmailChangeStore interface {
	UpdateEmailChangeToken(ctx context.Context, userID, tenantID, pendingEmail, tokenHash string, expiry time.Time) error
	GetUserByEmailChangeTokenHash(ctx context.Context, tokenHash string) (User, error)
	ApplyEmailChange(ctx context.Context, userID, tenantID string) error
	ClearEmailChangeToken(ctx context.Context, userID, tenantID string) error
}

EmailChangeStore persists pending email change flow.

type EmailVerificationInput

type EmailVerificationInput struct {
	UserID   string
	TenantID string
}

type EmailVerificationStore

type EmailVerificationStore interface {
	UpdateEmailVerificationToken(ctx context.Context, userID, tenantID, tokenHash string, expiry time.Time) error
	GetUserByEmailVerificationTokenHash(ctx context.Context, tokenHash string) (User, error)
	MarkEmailVerified(ctx context.Context, userID, tenantID string, verified bool) error
	ClearEmailVerificationToken(ctx context.Context, userID, tenantID string) error
}

EmailVerificationStore persists verification flow.

type Event

type Event struct {
	Name      string
	UserID    string
	TenantID  string
	Timestamp time.Time
	Data      map[string]any
}

Event is a generic auth domain event payload.

type EventBus

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

EventBus is a tiny in-process pub/sub for auth events.

func NewEventBus

func NewEventBus() *EventBus

func (*EventBus) Publish

func (b *EventBus) Publish(ev Event)

func (*EventBus) Subscribe

func (b *EventBus) Subscribe(event string, handler func(Event))

type ForgotPasswordInput

type ForgotPasswordInput struct {
	Email    string
	TenantID string
}

type HTTPMailerTransport

type HTTPMailerTransport struct {
	EndpointURL string
	Secret      string
	// contains filtered or unexported fields
}

HTTPMailerTransport sends mail via any HTTP endpoint (no SMTP needed).

func NewHTTPMailerTransport

func NewHTTPMailerTransport(endpointURL, secret string) *HTTPMailerTransport

NewHTTPMailerTransport creates a transport that POSTs to a webhook-style HTTP endpoint.

func (*HTTPMailerTransport) Send

type IDP

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

IDP is an OIDC Identity Provider.

func NewIDP

func NewIDP(cfg IDPConfig, authSvc *Service, clients ...IDPClient) (*IDP, error)

NewIDP creates a new OIDC IDP backed by the given auth service.

func (*IDP) RegisterHandlers

func (idp *IDP) RegisterHandlers(mux *http.ServeMux, basePath string)

RegisterHandlers mounts OIDC endpoints on the given mux.

type IDPClient

type IDPClient struct {
	ClientID     string
	ClientSecret string
	RedirectURIs []string
	Name         string
}

IDPClient represents a registered OIDC client application.

type IDPConfig

type IDPConfig struct {
	Issuer         string
	AccessTokenTTL time.Duration
	IDTokenTTL     time.Duration
}

IDPConfig configures the OIDC Identity Provider.

type LinkedAccountStore

type LinkedAccountStore interface {
	Save(ctx context.Context, link OAuthLinkedAccount) error
	FindByProvider(ctx context.Context, provider, providerID string) (OAuthLinkedAccount, error)
	ListForUser(ctx context.Context, userID string) ([]OAuthLinkedAccount, error)
	Delete(ctx context.Context, id string) error
}

LinkedAccountStore persists OAuth provider associations per user.

type LoginInput

type LoginInput struct {
	Email    string
	Password string
	TenantID string
}

LoginInput is the payload used for user authentication.

type MCPServer

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

MCPServer exposes auth configuration as MCP tools for AI editors. It speaks JSON-RPC 2.0 over HTTP and implements the Model Context Protocol tools/list and tools/call methods.

func NewMCPServer

func NewMCPServer(authSvc *Service) *MCPServer

NewMCPServer creates an MCP server wrapping an auth service.

func (*MCPServer) ServeHTTP

func (m *MCPServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles MCP JSON-RPC 2.0 requests (tools/list, tools/call).

type MagicLinkSendInput

type MagicLinkSendInput struct {
	Email    string
	TenantID string
}

type MagicLinkStore

type MagicLinkStore interface {
	UpdateMagicLinkToken(ctx context.Context, userID, tenantID, tokenHash string, expiry time.Time) error
	GetUserByMagicLinkTokenHash(ctx context.Context, tokenHash string) (User, error)
	ClearMagicLinkToken(ctx context.Context, userID, tenantID string) error
}

MagicLinkStore persists magic link state.

type MagicLinkVerifyInput

type MagicLinkVerifyInput struct {
	Token string
}

type MailMessage

type MailMessage struct {
	To      string
	Subject string
	Body    string
	IsHTML  bool
}

MailMessage is a single email to be sent.

type MailTemplateData

type MailTemplateData struct {
	AppName  string
	UserName string
	Token    string
	URL      string
	Code     string
	Extra    map[string]any
}

MailTemplateData holds the common variables injected into mail templates.

type MailTemplater

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

MailTemplater renders localized mail templates.

func NewMailTemplater

func NewMailTemplater(appName string) *MailTemplater

NewMailTemplater creates a templater with built-in en and it templates.

func (*MailTemplater) Render

func (m *MailTemplater) Render(locale, name string, data MailTemplateData) (subject, body string, err error)

Render produces the subject and HTML body for the given locale and template name.

type MailerTransport

type MailerTransport interface {
	Send(ctx context.Context, msg MailMessage) error
}

MailerTransport delivers email messages.

type MemoryLinkedAccounts

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

MemoryLinkedAccounts is an in-memory implementation of LinkedAccountStore, suitable for development, testing, and embedded deployments.

func NewMemoryLinkedAccounts

func NewMemoryLinkedAccounts() *MemoryLinkedAccounts

NewMemoryLinkedAccounts creates an in-memory LinkedAccountStore.

func (*MemoryLinkedAccounts) Delete

func (m *MemoryLinkedAccounts) Delete(_ context.Context, id string) error

func (*MemoryLinkedAccounts) FindByProvider

func (m *MemoryLinkedAccounts) FindByProvider(_ context.Context, provider, providerID string) (OAuthLinkedAccount, error)

func (*MemoryLinkedAccounts) ListForUser

func (m *MemoryLinkedAccounts) ListForUser(_ context.Context, userID string) ([]OAuthLinkedAccount, error)

func (*MemoryLinkedAccounts) Save

type MemoryMetadataStore

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

MemoryMetadataStore is an in-memory implementation of UserMetadataStore.

func NewMemoryMetadataStore

func NewMemoryMetadataStore() *MemoryMetadataStore

func (*MemoryMetadataStore) ClearMetadata

func (s *MemoryMetadataStore) ClearMetadata(_ context.Context, userID string) error

func (*MemoryMetadataStore) GetMetadata

func (s *MemoryMetadataStore) GetMetadata(_ context.Context, userID string) (map[string]any, error)

func (*MemoryMetadataStore) UpdateMetadata

func (s *MemoryMetadataStore) UpdateMetadata(_ context.Context, userID string, metadata map[string]any) error

type MemoryRolesPermissionsStore

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

MemoryRolesPermissionsStore is an in-memory RBAC store.

func NewMemoryRolesPermissionsStore

func NewMemoryRolesPermissionsStore() *MemoryRolesPermissionsStore

func (*MemoryRolesPermissionsStore) AddPermissionToRole

func (s *MemoryRolesPermissionsStore) AddPermissionToRole(_ context.Context, role, permission string) error

func (*MemoryRolesPermissionsStore) AddRoleToUser

func (s *MemoryRolesPermissionsStore) AddRoleToUser(_ context.Context, userID, role string, tenantID string) error

func (*MemoryRolesPermissionsStore) CreateRole

func (s *MemoryRolesPermissionsStore) CreateRole(_ context.Context, role string, permissions []string) error

func (*MemoryRolesPermissionsStore) DeleteRole

func (s *MemoryRolesPermissionsStore) DeleteRole(_ context.Context, role string) error

func (*MemoryRolesPermissionsStore) GetPermissionsForRole

func (s *MemoryRolesPermissionsStore) GetPermissionsForRole(_ context.Context, role string) ([]string, error)

func (*MemoryRolesPermissionsStore) GetPermissionsForUser

func (s *MemoryRolesPermissionsStore) GetPermissionsForUser(ctx context.Context, userID, tenantID string) ([]string, error)

func (*MemoryRolesPermissionsStore) GetRolesForUser

func (s *MemoryRolesPermissionsStore) GetRolesForUser(_ context.Context, userID, tenantID string) ([]string, error)

func (*MemoryRolesPermissionsStore) RemovePermissionFromRole

func (s *MemoryRolesPermissionsStore) RemovePermissionFromRole(_ context.Context, role, permission string) error

func (*MemoryRolesPermissionsStore) RemoveRoleFromUser

func (s *MemoryRolesPermissionsStore) RemoveRoleFromUser(_ context.Context, userID, role string, tenantID string) error

func (*MemoryRolesPermissionsStore) UserHasPermission

func (s *MemoryRolesPermissionsStore) UserHasPermission(ctx context.Context, userID, permission, tenantID string) (bool, error)

type MemorySessionStore

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

MemorySessionStore is a thread-safe in-memory implementation of SessionStore.

func NewMemorySessionStore

func NewMemorySessionStore() *MemorySessionStore

func (*MemorySessionStore) CreateSession

func (s *MemorySessionStore) CreateSession(_ context.Context, session Session) (Session, error)

func (*MemorySessionStore) DeleteExpiredSessions

func (s *MemorySessionStore) DeleteExpiredSessions(_ context.Context, now time.Time) (int, error)

func (*MemorySessionStore) GetSessionByID

func (s *MemorySessionStore) GetSessionByID(_ context.Context, sessionID string) (Session, error)

func (*MemorySessionStore) GetSessionByRefreshTokenHash

func (s *MemorySessionStore) GetSessionByRefreshTokenHash(_ context.Context, tokenHash string) (Session, error)

func (*MemorySessionStore) ListSessionsForUser

func (s *MemorySessionStore) ListSessionsForUser(_ context.Context, userID, tenantID string) ([]Session, error)

func (*MemorySessionStore) RevokeSessionByID

func (s *MemorySessionStore) RevokeSessionByID(_ context.Context, sessionID string) error

func (*MemorySessionStore) UpdateSession

func (s *MemorySessionStore) UpdateSession(_ context.Context, session Session) error

type MemoryTelemetryStore

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

MemoryTelemetryStore is an in-memory implementation of TelemetryStore.

func NewMemoryTelemetryStore

func NewMemoryTelemetryStore() *MemoryTelemetryStore

NewMemoryTelemetryStore creates an in-memory telemetry store.

func (*MemoryTelemetryStore) Query

func (*MemoryTelemetryStore) Record

type MemoryTenantStore

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

MemoryTenantStore is an in-memory tenant/membership store.

func NewMemoryTenantStore

func NewMemoryTenantStore() *MemoryTenantStore

func (*MemoryTenantStore) AssociateUserWithTenant

func (s *MemoryTenantStore) AssociateUserWithTenant(_ context.Context, userID, tenantID string) error

func (*MemoryTenantStore) CreateTenant

func (s *MemoryTenantStore) CreateTenant(_ context.Context, tenant Tenant) (Tenant, error)

func (*MemoryTenantStore) DeleteTenant

func (s *MemoryTenantStore) DeleteTenant(_ context.Context, id string) error

func (*MemoryTenantStore) DisassociateUserFromTenant

func (s *MemoryTenantStore) DisassociateUserFromTenant(_ context.Context, userID, tenantID string) error

func (*MemoryTenantStore) GetAllTenants

func (s *MemoryTenantStore) GetAllTenants(_ context.Context) ([]Tenant, error)

func (*MemoryTenantStore) GetTenantByID

func (s *MemoryTenantStore) GetTenantByID(_ context.Context, id string) (Tenant, error)

func (*MemoryTenantStore) GetTenantsForUser

func (s *MemoryTenantStore) GetTenantsForUser(_ context.Context, userID string) ([]Tenant, error)

func (*MemoryTenantStore) GetUsersForTenant

func (s *MemoryTenantStore) GetUsersForTenant(_ context.Context, tenantID string) ([]string, error)

func (*MemoryTenantStore) UpdateTenant

func (s *MemoryTenantStore) UpdateTenant(_ context.Context, id string, update Tenant) error

type MemoryUserStore

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

MemoryUserStore is a thread-safe in-memory implementation of UserStore.

func NewMemoryUserStore

func NewMemoryUserStore() *MemoryUserStore

func (*MemoryUserStore) ApplyEmailChange

func (s *MemoryUserStore) ApplyEmailChange(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) ClearEmailChangeToken

func (s *MemoryUserStore) ClearEmailChangeToken(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) ClearEmailVerificationToken

func (s *MemoryUserStore) ClearEmailVerificationToken(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) ClearMagicLinkToken

func (s *MemoryUserStore) ClearMagicLinkToken(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) ClearResetToken

func (s *MemoryUserStore) ClearResetToken(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) ClearSMSCode

func (s *MemoryUserStore) ClearSMSCode(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) CreateUser

func (s *MemoryUserStore) CreateUser(_ context.Context, user User) (User, error)

func (*MemoryUserStore) DeleteUser

func (s *MemoryUserStore) DeleteUser(_ context.Context, userID, tenantID string) error

func (*MemoryUserStore) GetUserByEmail

func (s *MemoryUserStore) GetUserByEmail(_ context.Context, email, tenantID string) (User, error)

func (*MemoryUserStore) GetUserByEmailChangeTokenHash

func (s *MemoryUserStore) GetUserByEmailChangeTokenHash(_ context.Context, tokenHash string) (User, error)

func (*MemoryUserStore) GetUserByEmailVerificationTokenHash

func (s *MemoryUserStore) GetUserByEmailVerificationTokenHash(_ context.Context, tokenHash string) (User, error)

func (*MemoryUserStore) GetUserByID

func (s *MemoryUserStore) GetUserByID(_ context.Context, id, tenantID string) (User, error)

func (*MemoryUserStore) GetUserByMagicLinkTokenHash

func (s *MemoryUserStore) GetUserByMagicLinkTokenHash(_ context.Context, tokenHash string) (User, error)

func (*MemoryUserStore) GetUserByResetTokenHash

func (s *MemoryUserStore) GetUserByResetTokenHash(_ context.Context, tokenHash string) (User, error)

func (*MemoryUserStore) GetUserBySMSCodeHash

func (s *MemoryUserStore) GetUserBySMSCodeHash(_ context.Context, userID, tenantID, codeHash string) (User, error)

func (*MemoryUserStore) MarkEmailVerified

func (s *MemoryUserStore) MarkEmailVerified(_ context.Context, userID, tenantID string, verified bool) error

func (*MemoryUserStore) UpdateEmailChangeToken

func (s *MemoryUserStore) UpdateEmailChangeToken(_ context.Context, userID, tenantID, pendingEmail, tokenHash string, expiry time.Time) error

func (*MemoryUserStore) UpdateEmailVerificationToken

func (s *MemoryUserStore) UpdateEmailVerificationToken(_ context.Context, userID, tenantID, tokenHash string, expiry time.Time) error

func (*MemoryUserStore) UpdateMagicLinkToken

func (s *MemoryUserStore) UpdateMagicLinkToken(_ context.Context, userID, tenantID, tokenHash string, expiry time.Time) error

func (*MemoryUserStore) UpdatePassword

func (s *MemoryUserStore) UpdatePassword(_ context.Context, userID, tenantID, passwordHash string) error

func (*MemoryUserStore) UpdateProfile

func (s *MemoryUserStore) UpdateProfile(_ context.Context, userID, tenantID, firstName, lastName string) (User, error)

func (*MemoryUserStore) UpdateResetToken

func (s *MemoryUserStore) UpdateResetToken(_ context.Context, userID, tenantID, tokenHash string, expiry time.Time) error

func (*MemoryUserStore) UpdateSMSCode

func (s *MemoryUserStore) UpdateSMSCode(_ context.Context, userID, tenantID, codeHash string, expiry time.Time) error

func (*MemoryUserStore) UpdateTOTPSecret

func (s *MemoryUserStore) UpdateTOTPSecret(_ context.Context, userID, tenantID, secret string, enabled bool) error

type OAuthLinkedAccount

type OAuthLinkedAccount struct {
	ID         string
	UserID     string
	Provider   string
	ProviderID string
	CreatedAt  time.Time
}

OAuthLinkedAccount stores a linked provider<->user association.

type OAuthPendingMeta

type OAuthPendingMeta struct {
	Provider    string
	RedirectURL string
	TenantID    string
	UserID      string // non-empty when linking to existing account
}

OAuthPendingMeta is the metadata stored during OAuth flow.

type OAuthProvider

type OAuthProvider struct {
	Name         string
	ClientID     string
	ClientSecret string
	RedirectURL  string
	AuthURL      string
	TokenURL     string
	UserInfoURL  string
	Scopes       []string
}

OAuthProvider holds configuration for a single OAuth 2.0 provider.

func GitHubProvider

func GitHubProvider(clientID, clientSecret, redirectURL string) OAuthProvider

GitHubProvider builds a pre-configured GitHub OAuth2 provider.

func GoogleProvider

func GoogleProvider(clientID, clientSecret, redirectURL string) OAuthProvider

GoogleProvider builds a pre-configured Google OAuth2 provider.

type OAuthService

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

OAuthService handles OAuth 2.0 authorization code flow.

func NewOAuthService

func NewOAuthService(providers ...OAuthProvider) *OAuthService

NewOAuthService creates an OAuthService for the given providers.

func (*OAuthService) AuthorizeURL

func (s *OAuthService) AuthorizeURL(providerName, state string) (string, error)

AuthorizeURL builds the redirect URL for the given provider and state token.

func (*OAuthService) ExchangeCode

func (s *OAuthService) ExchangeCode(ctx context.Context, providerName, code string) (OAuthUserInfo, error)

ExchangeCode exchanges an authorization code for user info.

func (*OAuthService) HandleCallback

func (s *OAuthService) HandleCallback(
	ctx context.Context,
	authSvc *Service,
	linkedAccounts LinkedAccountStore,
	info OAuthUserInfo,
	tenantID string,
	linkToUserID string,
) (User, AuthTokens, error)

HandleCallback resolves/creates a user after OAuth callback. If linkToUserID is non-empty the provider is linked to that existing account.

type OAuthUserInfo

type OAuthUserInfo struct {
	ProviderID string
	Provider   string
	Email      string
	Name       string
	AvatarURL  string
	Raw        map[string]any
}

OAuthUserInfo is the normalized profile returned after token exchange.

type OpenAPIInfo

type OpenAPIInfo struct {
	Title       string
	Description string
	Version     string
	ServerURL   string
}

OpenAPIInfo holds metadata for the generated OpenAPI spec.

type Option

type Option func(*authBuilder) error

Option configures Auth initialization.

func WithIssuer

func WithIssuer(issuer string) Option

WithIssuer configures token issuer.

func WithLogger

func WithLogger(fn func(format string, args ...any)) Option

WithLogger provides optional library logging callback.

func WithMetadataProvider

func WithMetadataProvider(store UserMetadataStore) Option

WithMetadataProvider wires optional metadata support.

func WithRBACProvider

func WithRBACProvider(store RolesPermissionsStore) Option

WithRBACProvider wires optional role/permission support.

func WithRequire2FA

func WithRequire2FA(enabled bool) Option

WithRequire2FA enables mandatory second-factor login checks.

func WithSecret

func WithSecret(secret string) Option

WithSecret configures the JWT signing secret.

func WithSessionStore

func WithSessionStore(store SessionStore) Option

WithSessionStore sets a custom SessionStore implementation.

func WithTenantProvider

func WithTenantProvider(store TenantStore) Option

WithTenantProvider wires optional tenant support.

func WithTokenClaimsBuilder

func WithTokenClaimsBuilder(fn func(ctx context.Context, user User) (map[string]any, error)) Option

WithTokenClaimsBuilder customizes token claims creation.

func WithTokenTTLs

func WithTokenTTLs(access, refresh time.Duration) Option

WithTokenTTLs configures access and refresh TTL.

func WithUserStore

func WithUserStore(store UserStore) Option

WithUserStore sets a custom UserStore implementation.

type PendingLinkStore

type PendingLinkStore interface {
	Save(ctx context.Context, state string, meta OAuthPendingMeta, ttl time.Duration) error
	Get(ctx context.Context, state string) (OAuthPendingMeta, error)
	Delete(ctx context.Context, state string) error
}

PendingLinkStore holds temporary OAuth link state.

type PublicTenant

type PublicTenant struct {
	ID        string    `json:"id"`
	Name      string    `json:"name"`
	IsActive  bool      `json:"isActive"`
	CreatedAt time.Time `json:"createdAt"`
}

PublicTenant is the response-safe projection of Tenant. The tenant Config blob is server-side configuration and is never serialised.

type PublicUser

type PublicUser struct {
	ID              string         `json:"id"`
	Email           string         `json:"email"`
	TenantID        string         `json:"tenantId,omitempty"`
	FirstName       string         `json:"firstName,omitempty"`
	LastName        string         `json:"lastName,omitempty"`
	PhoneNumber     string         `json:"phoneNumber,omitempty"`
	IsEmailVerified bool           `json:"isEmailVerified"`
	IsTOTPEnabled   bool           `json:"isTotpEnabled"`
	Roles           []string       `json:"roles,omitempty"`
	Permissions     []string       `json:"permissions,omitempty"`
	Tenants         []PublicTenant `json:"tenants,omitempty"`
	Metadata        map[string]any `json:"metadata,omitempty"`
	CustomClaims    map[string]any `json:"customClaims,omitempty"`
	CreatedAt       time.Time      `json:"createdAt"`
}

PublicUser is the response-safe projection of User. It is the only user shape adapters may serialise: credential material (password hash, TOTP secret, one-time token hashes and the pending email change) is deliberately absent.

func NewPublicUser

func NewPublicUser(user User) PublicUser

NewPublicUser projects a User onto its response-safe representation.

type RegisterInput

type RegisterInput struct {
	Email    string
	Password string
	TenantID string
}

RegisterInput is the payload to create a user and initial session.

type ResetPasswordInput

type ResetPasswordInput struct {
	Token       string
	NewPassword string
}

type RolesPermissionsStore

type RolesPermissionsStore interface {
	AddRoleToUser(ctx context.Context, userID, role string, tenantID string) error
	RemoveRoleFromUser(ctx context.Context, userID, role string, tenantID string) error
	GetRolesForUser(ctx context.Context, userID, tenantID string) ([]string, error)
	CreateRole(ctx context.Context, role string, permissions []string) error
	DeleteRole(ctx context.Context, role string) error
	AddPermissionToRole(ctx context.Context, role, permission string) error
	RemovePermissionFromRole(ctx context.Context, role, permission string) error
	GetPermissionsForRole(ctx context.Context, role string) ([]string, error)
	GetPermissionsForUser(ctx context.Context, userID, tenantID string) ([]string, error)
	UserHasPermission(ctx context.Context, userID, permission, tenantID string) (bool, error)
}

RolesPermissionsStore manages RBAC assignments and permissions.

type SMSCodeSendInput

type SMSCodeSendInput struct {
	UserID   string
	Email    string
	TenantID string
}

type SMSCodeVerifyInput

type SMSCodeVerifyInput struct {
	UserID   string
	Email    string
	TenantID string
	Code     string
}

type SMSStore

type SMSStore interface {
	UpdateSMSCode(ctx context.Context, userID, tenantID, codeHash string, expiry time.Time) error
	GetUserBySMSCodeHash(ctx context.Context, userID, tenantID, codeHash string) (User, error)
	ClearSMSCode(ctx context.Context, userID, tenantID string) error
}

SMSStore persists sms code state.

type Service

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

Service is the main entry point for authentication operations.

func NewService

func NewService(cfg Config, users UserStore, sessions SessionStore, opts ...ServiceOption) (*Service, error)

NewService builds an auth service with validated configuration.

func (*Service) AddUserToTenant

func (s *Service) AddUserToTenant(ctx context.Context, userID, tenantID string) error

func (*Service) AssignRole

func (s *Service) AssignRole(ctx context.Context, userID, role, tenantID string) error

func (*Service) ChangePassword

func (s *Service) ChangePassword(ctx context.Context, in ChangePasswordInput) error

func (*Service) CleanupExpiredSessions

func (s *Service) CleanupExpiredSessions(ctx context.Context) (int, error)

func (*Service) ConfirmEmailChange

func (s *Service) ConfirmEmailChange(ctx context.Context, in ConfirmEmailChangeInput) error

func (*Service) CreateRole

func (s *Service) CreateRole(ctx context.Context, role string, permissions []string) error

func (*Service) CreateTenant

func (s *Service) CreateTenant(ctx context.Context, name string, config map[string]any) (Tenant, error)

func (*Service) DeleteAccount

func (s *Service) DeleteAccount(ctx context.Context, in DeleteAccountInput) error

func (*Service) DisableTOTP

func (s *Service) DisableTOTP(ctx context.Context, userID, tenantID string) error

func (*Service) ForgotPassword

func (s *Service) ForgotPassword(ctx context.Context, in ForgotPasswordInput) (string, error)

func (*Service) GetMetadata

func (s *Service) GetMetadata(ctx context.Context, userID string) (map[string]any, error)

func (*Service) ListSessions

func (s *Service) ListSessions(ctx context.Context, userID, tenantID string) ([]Session, error)

func (*Service) Login

func (s *Service) Login(ctx context.Context, in LoginInput) (User, AuthTokens, error)

func (*Service) Logout

func (s *Service) Logout(ctx context.Context, refreshToken string) error

func (*Service) Me

func (s *Service) Me(ctx context.Context, accessToken string) (User, error)

func (*Service) Refresh

func (s *Service) Refresh(ctx context.Context, refreshToken string) (AuthTokens, error)

func (*Service) Register

func (s *Service) Register(ctx context.Context, in RegisterInput) (User, AuthTokens, error)

func (*Service) RequestEmailChange

func (s *Service) RequestEmailChange(ctx context.Context, in ChangeEmailRequestInput) (string, error)

func (*Service) ResetPassword

func (s *Service) ResetPassword(ctx context.Context, in ResetPasswordInput) error

func (*Service) RevokeSessionByID

func (s *Service) RevokeSessionByID(ctx context.Context, sessionID string) error
func (s *Service) SendMagicLink(ctx context.Context, in MagicLinkSendInput) (string, error)

func (*Service) SendSMSCode

func (s *Service) SendSMSCode(ctx context.Context, in SMSCodeSendInput) (string, error)

func (*Service) SendVerificationEmailToken

func (s *Service) SendVerificationEmailToken(ctx context.Context, in EmailVerificationInput) (string, error)

func (*Service) SetupTOTP

func (s *Service) SetupTOTP(ctx context.Context, userID, tenantID string) (string, error)

func (*Service) UpdateMetadata

func (s *Service) UpdateMetadata(ctx context.Context, userID string, metadata map[string]any) error

func (*Service) UpdateProfile

func (s *Service) UpdateProfile(ctx context.Context, in UpdateProfileInput) (User, error)

func (*Service) UserHasPermission

func (s *Service) UserHasPermission(ctx context.Context, userID, permission, tenantID string) (bool, error)

func (*Service) VerifyEmail

func (s *Service) VerifyEmail(ctx context.Context, in VerifyEmailInput) error
func (s *Service) VerifyMagicLink(ctx context.Context, in MagicLinkVerifyInput) (User, AuthTokens, error)

func (*Service) VerifySMSCode

func (s *Service) VerifySMSCode(ctx context.Context, in SMSCodeVerifyInput) (User, AuthTokens, error)

func (*Service) VerifyTOTP

func (s *Service) VerifyTOTP(ctx context.Context, userID, tenantID, code string) (User, AuthTokens, error)

func (*Service) VerifyTOTPSetup

func (s *Service) VerifyTOTPSetup(ctx context.Context, userID, tenantID, secret, code string) error

type ServiceOption

type ServiceOption func(*Service)

func WithMetadataStore

func WithMetadataStore(store UserMetadataStore) ServiceOption

func WithRolesPermissionsStore

func WithRolesPermissionsStore(store RolesPermissionsStore) ServiceOption

func WithTenantStore

func WithTenantStore(store TenantStore) ServiceOption

type Session

type Session struct {
	ID               string
	UserID           string
	TenantID         string
	RefreshTokenHash string
	CreatedAt        time.Time
	ExpiresAt        time.Time
	RevokedAt        *time.Time
}

Session stores refresh-token bound session metadata.

type SessionAdminStore

type SessionAdminStore interface {
	ListSessionsForUser(ctx context.Context, userID, tenantID string) ([]Session, error)
	RevokeSessionByID(ctx context.Context, sessionID string) error
	DeleteExpiredSessions(ctx context.Context, now time.Time) (int, error)
}

SessionAdminStore exposes session listing and cleanup primitives.

type SessionLookupStore

type SessionLookupStore interface {
	GetSessionByID(ctx context.Context, sessionID string) (Session, error)
}

SessionLookupStore resolves sessions by session ID.

type SessionStore

type SessionStore interface {
	CreateSession(ctx context.Context, session Session) (Session, error)
	GetSessionByRefreshTokenHash(ctx context.Context, tokenHash string) (Session, error)
	UpdateSession(ctx context.Context, session Session) error
}

SessionStore persists refresh-token sessions.

type SseDistributor

type SseDistributor interface {
	Publish(ctx context.Context, channel string, msg SseMessage) error
	Subscribe(ctx context.Context, channel string) (<-chan SseMessage, error)
}

SseDistributor broadcasts SSE messages to all connected clients. Implement this interface for Redis/Kafka-based multi-instance scaling.

type SseHub

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

SseHub manages in-process SSE subscriptions.

func NewSseHub

func NewSseHub() *SseHub

NewSseHub creates an in-process SSE hub.

func (*SseHub) Publish

func (h *SseHub) Publish(_ context.Context, channel string, msg SseMessage) error

Publish sends a message to all subscribers of channel.

func (*SseHub) Subscribe

func (h *SseHub) Subscribe(_ context.Context, channel string) (<-chan SseMessage, error)

Subscribe registers a new client channel for the given user/channel key.

func (*SseHub) Unsubscribe

func (h *SseHub) Unsubscribe(channel string, ch <-chan SseMessage)

Unsubscribe removes a client channel from the hub.

type SseMessage

type SseMessage struct {
	ID    string
	Event string
	Data  map[string]any
}

SseMessage is a single SSE payload.

type TOTPStore

type TOTPStore interface {
	UpdateTOTPSecret(ctx context.Context, userID, tenantID, secret string, enabled bool) error
}

TOTPStore persists authenticator setup.

type TelemetryEvent

type TelemetryEvent struct {
	ID        string
	EventName string
	UserID    string
	TenantID  string
	IP        string
	UserAgent string
	Success   bool
	Error     string
	Timestamp time.Time
	Meta      map[string]any
}

TelemetryEvent represents a single persisted auth event for analytics.

type TelemetryFilter

type TelemetryFilter struct {
	UserID    string
	TenantID  string
	EventName string
	Since     time.Time
	Until     time.Time
	Limit     int
}

TelemetryFilter restricts query results.

type TelemetryStore

type TelemetryStore interface {
	Record(ctx context.Context, event TelemetryEvent) error
	Query(ctx context.Context, filter TelemetryFilter) ([]TelemetryEvent, error)
}

TelemetryStore persists auth telemetry events.

type Tenant

type Tenant struct {
	ID        string
	Name      string
	IsActive  bool
	Config    map[string]any
	CreatedAt time.Time
}

Tenant represents an isolated workspace or organization.

type TenantStore

type TenantStore interface {
	CreateTenant(ctx context.Context, tenant Tenant) (Tenant, error)
	GetTenantByID(ctx context.Context, id string) (Tenant, error)
	GetAllTenants(ctx context.Context) ([]Tenant, error)
	UpdateTenant(ctx context.Context, id string, update Tenant) error
	DeleteTenant(ctx context.Context, id string) error
	AssociateUserWithTenant(ctx context.Context, userID, tenantID string) error
	DisassociateUserFromTenant(ctx context.Context, userID, tenantID string) error
	GetTenantsForUser(ctx context.Context, userID string) ([]Tenant, error)
	GetUsersForTenant(ctx context.Context, tenantID string) ([]string, error)
}

TenantStore manages tenants and user memberships.

type UpdateProfileInput

type UpdateProfileInput struct {
	UserID    string
	TenantID  string
	FirstName string
	LastName  string
}

type User

type User struct {
	ID                           string
	Email                        string
	PasswordHash                 string
	TenantID                     string
	PhoneNumber                  string
	FirstName                    string
	LastName                     string
	Role                         string
	IsEmailVerified              bool
	Require2FA                   bool
	IsTOTPEnabled                bool
	TOTPSecret                   string
	ResetTokenHash               string
	ResetTokenExpiresAt          *time.Time
	MagicLinkTokenHash           string
	MagicLinkTokenExpiresAt      *time.Time
	SMSCodeHash                  string
	SMSCodeExpiresAt             *time.Time
	EmailVerificationTokenHash   string
	EmailVerificationTokenExpiry *time.Time
	PendingEmail                 string
	EmailChangeTokenHash         string
	EmailChangeTokenExpiry       *time.Time
	Metadata                     map[string]any
	Roles                        []string
	Permissions                  []string
	Tenants                      []Tenant
	CustomClaims                 map[string]any
	CreatedAt                    time.Time
	UpdatedAt                    time.Time
}

User is the canonical identity model.

type UserAccountStore

type UserAccountStore interface {
	UpdateProfile(ctx context.Context, userID, tenantID, firstName, lastName string) (User, error)
	DeleteUser(ctx context.Context, userID, tenantID string) error
}

UserAccountStore adds account lifecycle operations.

type UserMetadataStore

type UserMetadataStore interface {
	GetMetadata(ctx context.Context, userID string) (map[string]any, error)
	UpdateMetadata(ctx context.Context, userID string, metadata map[string]any) error
	ClearMetadata(ctx context.Context, userID string) error
}

UserMetadataStore manages arbitrary key/value user metadata.

type UserPasswordStore

type UserPasswordStore interface {
	UpdatePassword(ctx context.Context, userID, tenantID, passwordHash string) error
	UpdateResetToken(ctx context.Context, userID, tenantID, tokenHash string, expiry time.Time) error
	GetUserByResetTokenHash(ctx context.Context, tokenHash string) (User, error)
	ClearResetToken(ctx context.Context, userID, tenantID string) error
}

UserPasswordStore adds password lifecycle methods.

type UserStore

type UserStore interface {
	CreateUser(ctx context.Context, user User) (User, error)
	GetUserByEmail(ctx context.Context, email, tenantID string) (User, error)
	GetUserByID(ctx context.Context, id, tenantID string) (User, error)
}

UserStore persists and resolves users.

type VerifyEmailInput

type VerifyEmailInput struct {
	Token string
}

type WebhookDispatcher

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

WebhookDispatcher delivers signed webhook payloads.

func NewWebhookDispatcher

func NewWebhookDispatcher(endpoints ...WebhookEndpoint) *WebhookDispatcher

NewWebhookDispatcher creates a dispatcher for the given endpoints.

func (*WebhookDispatcher) Dispatch

func (d *WebhookDispatcher) Dispatch(ctx context.Context, event Event)

Dispatch delivers the event to all matching endpoints.

type WebhookEndpoint

type WebhookEndpoint struct {
	ID     string
	URL    string
	Secret string
	Events []string // event names to forward; empty = all
}

WebhookEndpoint configures a single outbound webhook target.

type WebhookPayload

type WebhookPayload struct {
	ID        string         `json:"id"`
	Event     string         `json:"event"`
	Timestamp time.Time      `json:"timestamp"`
	Data      map[string]any `json:"data"`
}

WebhookPayload is the envelope sent to webhook targets.

Directories

Path Synopsis
adapter
chi
gin

Jump to

Keyboard shortcuts

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