keyauth

package
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: Apr 6, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package keyauth provides API key authentication middleware for celeris.

The middleware extracts an API key from a configurable source (header, query parameter, cookie, form field, or URL parameter), validates it via a user-supplied function, and stores the authenticated key in the context store under ContextKey ("keyauth_key"). Failed authentication returns 401 with a WWW-Authenticate header.

Config.Validator is required; omitting it panics at initialization.

Simple usage with static keys (constant-time comparison):

server.Use(keyauth.New(keyauth.Config{
    Validator: keyauth.StaticKeys("key-1", "key-2"),
}))

Custom validator with context access:

server.Use(keyauth.New(keyauth.Config{
    Validator: func(c *celeris.Context, key string) (bool, error) {
        return checkDB(c, key)
    },
    KeyLookup: "query:api_key",
}))

Multiple sources can be comma-separated for fallback:

KeyLookup: "header:Authorization:Bearer ,query:api_key"

Use KeyFromContext to retrieve the authenticated key downstream.

Config.ChallengeParams controls RFC 6750 parameters in the WWW-Authenticate header (error, error_description, error_uri, scope).

StaticKeys uses constant-time comparison via crypto/subtle to prevent timing side-channels.

ErrUnauthorized and ErrMissingKey are exported sentinel errors (both 401) usable with errors.Is for upstream error handling.

Set Config.Skip to bypass the middleware dynamically, or Config.SkipPaths for exact-match path exclusions.

Security: API keys in query strings (`query:api_key`) are logged in access logs, browser history, and Referer headers. Prefer header-based key lookup for sensitive environments.

Index

Examples

Constants

View Source
const ContextKey = "keyauth_key"

ContextKey is the context store key for the authenticated API key.

Variables

View Source
var ErrMissingKey = &celeris.HTTPError{Code: 401, Message: "Unauthorized", Err: errors.New("keyauth: missing API key")}

ErrMissingKey is returned when no API key is found in the request. Do not mutate: this is a shared sentinel value used with errors.Is.

View Source
var ErrUnauthorized = celeris.NewHTTPError(401, "Unauthorized")

ErrUnauthorized is returned when the API key is invalid. Do not mutate: this is a shared sentinel value used with errors.Is.

Functions

func KeyFromContext

func KeyFromContext(c *celeris.Context) string

KeyFromContext returns the authenticated API key from the context store. Returns an empty string if no key was stored (e.g., no auth or skipped).

func New

func New(config ...Config) celeris.HandlerFunc

New creates a key auth middleware with the given config.

Example
package main

import (
	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Static API keys with constant-time comparison.
	_ = keyauth.New(keyauth.Config{
		Validator: keyauth.StaticKeys("key-1", "key-2"),
	})
}
Example (CustomValidator)
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Custom validator with context access.
	_ = keyauth.New(keyauth.Config{
		Validator: func(c *celeris.Context, key string) (bool, error) {
			tenant := c.Header("x-tenant")
			_ = tenant // look up key in tenant-specific store
			return key == "expected", nil
		},
	})
}
Example (ErrorHandler)
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Custom error handler for JSON responses.
	_ = keyauth.New(keyauth.Config{
		Validator: keyauth.StaticKeys("secret"),
		ErrorHandler: func(c *celeris.Context, err error) error {
			return c.JSON(401, map[string]string{"error": err.Error()})
		},
	})
}
Example (FormField)
package main

import (
	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Extract key from a form field (URL-encoded or multipart).
	_ = keyauth.New(keyauth.Config{
		KeyLookup: "form:api_key",
		Validator: keyauth.StaticKeys("form-secret"),
	})
}
Example (QueryParam)
package main

import (
	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Extract key from query parameter instead of header.
	_ = keyauth.New(keyauth.Config{
		KeyLookup: "query:api_key",
		Validator: keyauth.StaticKeys("my-secret-key"),
	})
}
Example (SuccessHandler)
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Enrich context after successful auth.
	_ = keyauth.New(keyauth.Config{
		Validator: keyauth.StaticKeys("admin-key"),
		SuccessHandler: func(c *celeris.Context) {
			c.Set("role", "admin")
		},
	})
}
Example (UrlParam)
package main

import (
	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Extract key from a URL path parameter (e.g., /api/:token/data).
	_ = keyauth.New(keyauth.Config{
		KeyLookup: "param:token",
		Validator: keyauth.StaticKeys("param-secret"),
	})
}
Example (WwwAuthenticate)
package main

import (
	"github.com/goceleris/celeris/middleware/keyauth"
)

func main() {
	// Custom WWW-Authenticate header with Bearer scheme.
	_ = keyauth.New(keyauth.Config{
		Validator:  keyauth.StaticKeys("secret"),
		AuthScheme: "Bearer",
		Realm:      "MyAPI",
	})
}

func StaticKeys

func StaticKeys(keys ...string) func(*celeris.Context, string) (bool, error)

StaticKeys returns a constant-time validator that checks the key against a fixed set of valid keys. All comparisons use a uniform code path to prevent timing side-channels on key existence or length.

Duplicate keys in the input are not deduplicated; each copy is compared independently. This has no effect on correctness.

Types

type Config

type Config struct {
	// Skip defines a function to skip this middleware for certain requests.
	Skip func(c *celeris.Context) bool

	// SkipPaths lists paths to skip (exact match).
	SkipPaths []string

	// KeyLookup defines where to extract the API key.
	//
	// Format: "source:name" or "source:name:prefix" for prefix stripping.
	// Multiple sources can be comma-separated for fallback, e.g.
	// "header:Authorization:Bearer ,query:api_key".
	//
	// Supported sources: header, query, cookie, form, param.
	// Default: "header:X-API-Key".
	KeyLookup string

	// Validator checks the extracted key. Required -- panics if nil.
	//
	// Implementations SHOULD use crypto/subtle.ConstantTimeCompare or
	// equivalent to prevent timing attacks. See StaticKeys for a
	// ready-made constant-time validator.
	Validator func(c *celeris.Context, key string) (bool, error)

	// SuccessHandler is called after a key is successfully validated,
	// before c.Next(). Use it to enrich the context (e.g., set tenant ID
	// based on key). If nil, no extra action is taken.
	SuccessHandler func(c *celeris.Context)

	// ErrorHandler handles authentication failures. Receives the error
	// (ErrMissingKey or ErrUnauthorized) and returns the error to propagate.
	// Default: returns the error as-is.
	ErrorHandler func(c *celeris.Context, err error) error

	// Realm is the realm value used in the WWW-Authenticate header on 401.
	// Default: "Restricted".
	Realm string

	// AuthScheme is the authentication scheme used in the WWW-Authenticate
	// header (e.g. "Bearer"). When empty, "ApiKey" is used as the scheme.
	AuthScheme string

	// ChallengeParams is a map of RFC 6750 parameters for the
	// WWW-Authenticate header. Common keys: "error", "error_description",
	// "error_uri", "scope". Values are emitted as quoted-string parameters
	// in sorted key order.
	//
	// The "error" value must be one of "invalid_request", "invalid_token",
	// or "insufficient_scope". "error_uri" must be a valid absolute URI.
	// "scope" tokens must be valid NQCHAR per RFC 6749 Appendix A.
	ChallengeParams map[string]string

	// ContinueOnIgnoredError, when true, allows the request to proceed
	// if ErrorHandler returns nil. This enables mixed public/private routes
	// where authentication is optional.
	ContinueOnIgnoredError bool
}

Config defines the key auth middleware configuration.

Jump to

Keyboard shortcuts

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