authhttp

package
v0.4.3 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: MIT Imports: 21 Imported by: 0

README

auth/http

auth/http adapts auth.Service to chi routes, bearer middleware, cookies, and JSON responses. Import path: github.com/Ithildur/EiluneKit/auth/http; package name: authhttp.

This package is for the default session auth flow used by admin dashboards, internal control planes, and shared-secret applications. Login uses JSON credentials and refresh cookies.

Quick Start

manager, err := authjwt.New(signingKey, authstore.NewMemoryStore())
if err != nil {
	return err
}

authHandler, err := authhttp.NewHandler(manager, authhttp.Options{
	LoginAuthenticator: authhttp.LoginAuthenticatorFunc(func(ctx context.Context, username, password string) (string, bool, error) {
		user, err := repo.FindByUsername(ctx, username)
		if err != nil {
			return "", false, err
		}
		if user == nil {
			return "", false, nil
		}

		computedHash := hashPassword(password, user.Salt)
		if !authhttp.VerifyCredential(user.PasswordHash, computedHash) {
			return "", false, nil
		}
		return user.ID, true, nil
	}),
})
if err != nil {
	return err
}

if err := authHandler.Register(r); err != nil {
	return err
}

POST /auth/login accepts username, password, and a required persistence field with persistent or session. LoginAuthenticator verifies the credentials; the handler returns an access token and sets refresh/CSRF cookies with matching persistence.

Static Credential

For a fixed shared secret:

staticAuth, err := authhttp.NewStaticPassword("dashboard-admin", adminPassword)
if err != nil {
	return err
}

authHandler, err := authhttp.NewHandler(manager, authhttp.Options{
	LoginAuthenticator: staticAuth,
})
if err != nil {
	return err
}
if err := authhttp.ValidateStaticPassword(adminPassword); err != nil {
	return err
}

This is the intended path for a single-admin dashboard or internal control plane. The request username may be ignored; the configured user ID becomes the token subject when the password matches.

Bearer Middleware

bearer, err := authhttp.RequireBearer(manager)
if err != nil {
	return err
}
r.Use(bearer)

RequireBearer accepts any AccessTokenValidator. It parses the HTTP Authorization: Bearer header in the HTTP layer, while jwt.Manager only validates the raw access token.

Use OptionalBearer when a public route may attach user claims but must still reject malformed or invalid tokens.

optionalBearer, err := authhttp.OptionalBearer(manager)
if err != nil {
	return err
}
route.Get("/feed", "List feed", feed, routes.Auth(routes.AuthOptional), routes.Use(optionalBearer))

API Key Middleware

nodeKey, err := authhttp.RequireAPIKey(authhttp.APIKeyValidatorFunc(func(ctx context.Context, key string) (bool, error) {
	return subtle.ConstantTimeCompare([]byte(key), []byte(nodeSecret)) == 1, nil
}), "X-Node-Secret")
if err != nil {
	return err
}
route.Get("/node/metrics", "Node metrics", metrics, routes.Auth(routes.AuthRequired), routes.Use(nodeKey))

An empty header name defaults to X-API-Key.

Routes

Default HTTP paths:

Route Auth Middleware
POST /auth/login public login rate limit, optional login lockout, body limit, JSON body
POST /auth/refresh required refresh-cookie + CSRF
POST /auth/logout required refresh-cookie + CSRF
GET /auth/sessions required RequireBearer
DELETE /auth/sessions/current required RequireBearer
DELETE /auth/sessions required RequireBearer
DELETE /auth/sessions/{sid} required RequireBearer

Handler.Routes() returns route declarations with authentication middleware for mounting and OpenAPI generation. GET /auth/sessions requires a manager that implements auth.SessionLister; auth/jwt.Manager supports it when the store supports session listing. DELETE /auth/sessions revokes the current user's sessions and clears stored session records when the manager supports cleanup.

routeList := authHandler.Routes()
err := routes.Mount(r, "", routeList)

spec, err := openapi.Generate(routeList, openapi.Options{
	Title:   "Application Auth API",
	Version: "1.0.0",
})

Options

  • LoginAuthenticator: required credential verification entrypoint
  • BasePath: *string route prefix; nil defaults to "/auth", new("") selects the root, and new("/api/auth") selects /api/auth. Non-empty prefixes require a single leading slash; trailing slashes and surrounding whitespace are rejected.
  • RefreshCookiePath: browser-visible absolute refresh-cookie path; defaults to / followed by the resolved BasePath
  • CSRFCookiePath: CSRF cookie path; default /
  • RefreshCookieName, CSRFCookieName, CSRFHeaderName: cookie and header names
  • CookieSameSite: optional auth cookie SameSite override; zero keeps automatic TLS/proxy-derived behavior
  • TrustedProxies: forwarded-header trust boundary for rate limiting and secure-cookie detection
  • MaxBodyBytes: request body size limit for auth endpoints
  • RateLimit: login rate-limit settings
  • LoginLockout: optional failed-login lockout. On credential failure it records the lockout key, returns 429 login_locked when the key reaches its threshold, and clears the key after a successful login.
  • LoginLockoutKeyFunc: optional key function for LoginLockout; the default key uses the exact client IP. When LoginLockout is set, the key must be non-empty. Include username only when LoginAuthenticator treats username as meaningful.
  • Events: auth lifecycle hooks. Events.Login runs after credentials are accepted and tokens are issued, but before cookies and response body are written; returning an error attempts to revoke the new refresh session and fails the login request. Hooks may be called concurrently.
  • Logger: optional *slog.Logger for auth lifecycle hook failures and revoke-compensation failures.

Forwarded headers are trusted only when TrustedProxies is set. The default rate-limit key uses RemoteAddr.

Use auth.NewMemoryLockout for single-process deployments:

authHandler, err := authhttp.NewHandler(manager, authhttp.Options{
	LoginAuthenticator: staticAuth,
	LoginLockout: auth.NewMemoryLockout(auth.MemoryLockoutOptions{
		MaxFailures: 5,
		Window:      15 * time.Minute,
		Lockout:     15 * time.Minute,
	}),
})

For multi-instance deployments, pass a Redis or SQL-backed auth.Lockout so failed-login state is shared across processes.

By default, cookie Secure and SameSite are derived from the request: TLS always enables secure cookies, and X-Forwarded-Proto: https only counts from trusted proxies. Set CookieSameSite when deployment policy needs an explicit mode, for example http.SameSiteLaxMode for same-site apps or http.SameSiteNoneMode for cross-site SPAs.

Contracts

  • NewHandler requires both a TokenManager and Options.LoginAuthenticator.
  • NewHandler takes one Options struct; fields other than LoginAuthenticator fall back to defaults when left zero-valued.
  • NewStaticPassword requires a non-empty user ID and password.
  • VerifyCredential performs exact byte comparison and is suitable for pre-hashed or application-derived credentials.
  • Use auth/rbac and auth/rbac/http when the application needs multiple users, roles, or scopes.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrAPIKeyValidatorMissing = errors.New("api key validator is required")

ErrAPIKeyValidatorMissing means an API-key middleware was built without a validator. ErrAPIKeyValidatorMissing 表示 API-key 中间件缺少 validator。

View Source
var ErrAccessTokenValidatorMissing = errors.New("access token validator is required")

ErrAccessTokenValidatorMissing means a Bearer middleware was built without a validator. ErrAccessTokenValidatorMissing 表示 Bearer 中间件缺少 token validator。

Functions

func LoginRateLimit

func LoginRateLimit(opts *RateLimitOptions) func(stdhttp.Handler) stdhttp.Handler

LoginRateLimit returns a login rate-limit middleware. Disabled or nil options return nil. LoginRateLimit 返回登录限流中间件。 传入 nil 或 Disabled 时返回 nil。

func OptionalBearer added in v0.1.7

func OptionalBearer(auth AccessTokenValidator) (func(stdhttp.Handler) stdhttp.Handler, error)

OptionalBearer returns middleware that attaches claims when a Bearer token is present. Missing Authorization is accepted; malformed or invalid tokens are rejected. OptionalBearer 返回 Bearer token 可选中间件。 未提供 Authorization 会继续执行;格式错误或 token 无效会被拒绝。

func RequireAPIKey added in v0.1.7

func RequireAPIKey(auth APIKeyValidator, header string) (func(stdhttp.Handler) stdhttp.Handler, error)

RequireAPIKey returns middleware that validates an API key from header. Empty header uses X-API-Key. RequireAPIKey 返回从 header 校验 API key 的中间件。 header 为空时使用 X-API-Key。

func RequireBearer

func RequireBearer(auth AccessTokenValidator) (func(stdhttp.Handler) stdhttp.Handler, error)

RequireBearer returns a Bearer-token middleware. Call bearer, err := RequireBearer(auth) and then r.Use(bearer). RequireBearer 返回 Bearer token 中间件。 调用 bearer, err := RequireBearer(auth),再执行 r.Use(bearer)。 Example / 示例:

bearer, err := authhttp.RequireBearer(jwtManager)
if err != nil { ... }
r.Use(bearer)

func ValidateStaticPassword added in v0.1.8

func ValidateStaticPassword(password string) error

ValidateStaticPassword validates a static password. NewHandler does not call it automatically. ValidateStaticPassword 校验静态密码。 NewHandler 不会自动调用它。

func VerifyCredential

func VerifyCredential(expected, got string) bool

VerifyCredential compares expected and got with an exact byte match. VerifyCredential 使用精确字节匹配比较 expected 和 got。

Types

type APIKeyValidator added in v0.1.7

type APIKeyValidator interface {
	ValidateAPIKey(ctx context.Context, key string) (bool, error)
}

APIKeyValidator validates API keys for RequireAPIKey. APIKeyValidator 为 RequireAPIKey 校验 API key。

type APIKeyValidatorFunc added in v0.1.7

type APIKeyValidatorFunc func(ctx context.Context, key string) (bool, error)

APIKeyValidatorFunc adapts a function to APIKeyValidator. APIKeyValidatorFunc 将函数适配为 APIKeyValidator。

func (APIKeyValidatorFunc) ValidateAPIKey added in v0.1.7

func (f APIKeyValidatorFunc) ValidateAPIKey(ctx context.Context, key string) (bool, error)

ValidateAPIKey calls f(ctx, key). ValidateAPIKey 调用 f(ctx, key)。

type AccessTokenValidator added in v0.1.5

type AccessTokenValidator = auth.AccessTokenValidator

AccessTokenValidator validates access tokens for RequireBearer. AccessTokenValidator 为 RequireBearer 校验 access token。

type Events added in v0.2.1

type Events struct {
	// Login runs after credentials are accepted and tokens are issued, but before cookies and response body are written.
	// If Login returns an error, Handler attempts to revoke the new refresh session and fails the request.
	// Login 在凭据通过且 token 已签发后、cookie 和响应体写出前执行。
	// 如果 Login 返回错误,Handler 会尝试吊销新的 refresh session 并让请求失败。
	Login func(context.Context, LoginEvent) error
}

Events configures Handler event hooks. Hooks may be called concurrently. Events 配置 Handler 事件 hook。 hook 可能并发调用。

type Handler

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

Handler serves auth endpoints. Handler 提供认证端点。

func NewHandler

func NewHandler(manager TokenManager, opts Options) (*Handler, error)

NewHandler returns a Handler. Call NewHandler(manager, opts). Zero-valued options fall back to DefaultOptions. NewHandler 返回 Handler。 调用 NewHandler(manager, opts)。 零值选项会回退到 DefaultOptions。

func (*Handler) Register

func (h *Handler) Register(r chi.Router) error

Register mounts the auth routes on r. Call Register(r) to mount routes with their auth middleware. Register 在 r 上挂载认证路由。 调用 Register(r) 挂载路由及其认证中间件。

func (*Handler) Routes

func (h *Handler) Routes() []routes.Route

Routes returns the auth routes. Returned routes already include their auth middleware. Nil Handler is invalid and panics. Routes 返回认证路由。 返回的路由已包含各自的认证中间件。 Nil Handler 无效,调用时会 panic。

type LoginAuthenticator

type LoginAuthenticator = auth.LoginAuthenticator

LoginAuthenticator validates login credentials. Implementations may ignore username. LoginAuthenticator 校验登录凭据。 实现可以忽略 username。

func NewStaticPassword added in v0.1.8

func NewStaticPassword(userID, expectedPassword string) (LoginAuthenticator, error)

NewStaticPassword returns a LoginAuthenticator for one fixed password. NewStaticPassword 返回基于固定密码的 LoginAuthenticator。

type LoginAuthenticatorFunc

type LoginAuthenticatorFunc = auth.LoginAuthenticatorFunc

LoginAuthenticatorFunc adapts a function to LoginAuthenticator. LoginAuthenticatorFunc 将函数适配为 LoginAuthenticator。

type LoginEvent added in v0.2.1

type LoginEvent struct {
	UserID           string
	Username         string
	SessionOnly      bool
	AccessExpiresAt  time.Time
	RefreshExpiresAt time.Time
}

LoginEvent describes a successful login before the response is written. LoginEvent 描述响应写出前的一次成功登录。

type Options

type Options struct {
	// LoginAuthenticator validates login credentials.
	// LoginAuthenticator 校验登录凭据。
	LoginAuthenticator LoginAuthenticator
	// BasePath is a route prefix. Nil defaults to "/auth"; new("") selects the root.
	// BasePath 是路由前缀;nil 默认使用 "/auth",new("") 选择根目录。
	BasePath *string
	// RefreshCookiePath defaults to the absolute HTTP path for BasePath when empty.
	// RefreshCookiePath 为空时默认使用 BasePath 对应的绝对 HTTP 路径。
	RefreshCookiePath string
	// CSRFCookiePath defaults to "/".
	// CSRFCookiePath 默认为 "/"。
	CSRFCookiePath string

	// RefreshCookieName is the refresh cookie name.
	// RefreshCookieName 是 refresh cookie 名。
	RefreshCookieName string
	// CSRFCookieName is the CSRF cookie name.
	// CSRFCookieName 是 CSRF cookie 名。
	CSRFCookieName string
	// CSRFHeaderName is the CSRF request header name.
	// CSRFHeaderName 是 CSRF 请求头名。
	CSRFHeaderName string
	// CookieSameSite overrides the derived auth cookie SameSite mode when non-zero.
	// CookieSameSite 非零时覆盖认证 cookie 自动推导的 SameSite 模式。
	CookieSameSite http.SameSite
	// TrustedProxies enables forwarded-header trust.
	// TrustedProxies 启用转发头信任。
	TrustedProxies []netip.Prefix

	// MaxBodyBytes limits the login body size.
	// MaxBodyBytes 限制登录请求体大小。
	MaxBodyBytes int64
	// RateLimit configures login rate limiting.
	// RateLimit 配置登录限流。
	RateLimit *RateLimitOptions
	// LoginLockout records failed logins and locks its key after too many failures.
	// LoginLockout 记录登录失败,并在失败过多后锁定对应 key。
	LoginLockout authcore.Lockout
	// LoginLockoutKeyFunc returns the lockout key for a login attempt.
	// The default key uses the client IP when LoginLockout is set.
	// When LoginLockout is set, the key must be non-empty.
	// LoginLockoutKeyFunc 返回一次登录尝试的锁定 key。
	// 设置 LoginLockout 时,默认 key 使用客户端 IP。
	// 设置 LoginLockout 时,key 不能为空。
	LoginLockoutKeyFunc func(*http.Request, string) string
	// Events configures auth lifecycle hooks.
	// Events 配置认证生命周期 hook。
	Events Events
	// Logger records auth lifecycle hook failures when set.
	// Logger 非空时记录认证生命周期 hook 失败。
	Logger *slog.Logger
}

Options configures NewHandler. Options 配置 NewHandler。

func DefaultOptions

func DefaultOptions() Options

DefaultOptions returns the default handler options. DefaultOptions 返回默认 handler 选项。

type RateLimitOptions

type RateLimitOptions struct {
	Disabled       bool
	Requests       int
	Window         time.Duration
	IPv4PrefixBits int
	IPv6PrefixBits int
	TrustedProxies []netip.Prefix
	KeyFunc        httprate.KeyFunc
}

RateLimitOptions configures LoginRateLimit. RateLimitOptions 配置 LoginRateLimit。

func DefaultRateLimitOptions

func DefaultRateLimitOptions() RateLimitOptions

DefaultRateLimitOptions returns the default login rate limit options. DefaultRateLimitOptions 返回默认登录限流选项。

type TokenManager

type TokenManager = auth.TokenManager

TokenManager provides the auth operations used by Handler. TokenManager 为 Handler 提供认证操作。

Jump to

Keyboard shortcuts

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