apikey

package module
v0.0.0-...-2f0770c Latest Latest
Warning

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

Go to latest
Published: Nov 9, 2025 License: MIT Imports: 8 Imported by: 0

README

chi-api-key-auth

A Chi middleware for API Key-based authorization.

Features

Support for Key Deprecation

What happens when a key needs to be rotated? Since deployments among services cannot be 100% synchronized, enforcing a new secret will cause requests using the old key version to be rejected.

The middleware supports two different secrets for both read/write and read-only scopes. In addition, the deprecated key can be supported for a limited period of time.

Support for read-only & read-write keys

The key scope can be differentiated based on well-known HTTP verbs, or by explicitly defining the list of allowed HTTP methods.

Secret Provider Abstraction

Secrets can be provided using environment variables, with configurable variable names. The secret provider can be swapped with any implementation supporting the given interface.

Examples

package main

import (
	"net/http"

	"github.com/go-chi/chi/v5"
	"github.com/go-chi/chi/v5/middleware"

	"github.com/georgepsarakis/chi-api-key-auth/apikey"
)

func main() {
	r := chi.NewRouter()
	r.Use(middleware.Logger)
	// By default, the following variable names are used for secrets:
	// - CHI_API_KEY
	// - CHI_API_KEY_READONLY
	// The Authorization/Bearer header scheme as a request secret provider.
	chiReadonlyOpts := apikey.NewReadonlyOptions()
	r.Group(func(r chi.Router) {
		r.Use(apikey.Authorize(chiReadonlyOpts))
		r.Get("/", func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte("welcome"))
		})
	})

	if err := http.ListenAndServe(":3000", r); err != nil {
		panic(err)
	}
}

Wrong authorization results in a response with 401 status code (default failure handler):

$ curl localhost:3000 --header 'Authorization: Bearer wrong-key'
2025/03/31 15:06:28 "GET http://localhost:3000/ HTTP/1.1" from [::1]:59751 - 401 0B in 21.583µs

A successfully authorized request:

$ curl localhost:3000 --header 'Authorization: Bearer test-api-key-auth'
2025/03/31 15:06:59 "GET http://localhost:3000/ HTTP/1.1" from [::1]:59755 - 200 7B in 12.125µs

Documentation

Index

Constants

View Source
const HeaderNameAuthorization = "Authorization"
View Source
const HeaderNameXApiKey = "X-Api-Key" // #nosec G101
View Source
const PermissionScopeReadWrite = PermissionScope("readwrite")
View Source
const PermissionScopeReadonly = PermissionScope("readonly")

Variables

This section is empty.

Functions

func Authorize

func Authorize(options Options) func(next http.Handler) http.Handler

Authorize implements a simple middleware handler for creating header-based authentication schemes.

func DefaultUnauthorizedHandler

func DefaultUnauthorizedHandler() http.HandlerFunc

func IsUnauthorized

func IsUnauthorized(ctx context.Context) bool

func NewUnauthorizedContext

func NewUnauthorizedContext(ctx context.Context) context.Context

Types

type AuthorizationHeader

type AuthorizationHeader struct {
	HeaderAuthProvider
}

func (AuthorizationHeader) Name

func (h AuthorizationHeader) Name() string

func (AuthorizationHeader) Secret

func (h AuthorizationHeader) Secret(r *http.Request) (string, bool)

type Authorizer

type Authorizer struct {
	SecretProvider              SecretProvider
	DeprecationExpirationPolicy DeprecationExpirationPolicy
	// contains filtered or unexported fields
}

func NewAuthorizer

func NewAuthorizer(secretProvider SecretProvider, deprecationPolicy DeprecationExpirationPolicy, scope PermissionScope, httpMethodsOverride []string) Authorizer

func NewReadonlyAuthorizer

func NewReadonlyAuthorizer(provider SecretProvider, httpMethods []string) Authorizer

func (Authorizer) IsValidRequest

func (a Authorizer) IsValidRequest(r *http.Request, requestKey string) bool

type DeprecationExpirationPolicy

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

func NewDeprecationExpirationPolicyFromEnvironment

func NewDeprecationExpirationPolicyFromEnvironment(variableName string) (DeprecationExpirationPolicy, error)

func NewDeprecationExpirationPolicyFromString

func NewDeprecationExpirationPolicyFromString(datetime string) (DeprecationExpirationPolicy, error)

func (DeprecationExpirationPolicy) Allow

type EnvironmentSecretProvider

type EnvironmentSecretProvider struct {
	SecretProvider
	CurrentSecretHeaderName            string
	DeprecatedSecretHeaderName         string
	ReadonlySecretHeaderName           string
	DeprecatedReadonlySecretHeaderName string
	// contains filtered or unexported fields
}

func NewEnvironmentSecretProviderReadWrite

func NewEnvironmentSecretProviderReadWrite(current, deprecated string) *EnvironmentSecretProvider

func NewEnvironmentSecretProviderReadonly

func NewEnvironmentSecretProviderReadonly(readonly, deprecatedReadonly string) *EnvironmentSecretProvider

func (EnvironmentSecretProvider) GetCurrentReadonlySecret

func (p EnvironmentSecretProvider) GetCurrentReadonlySecret() string

func (EnvironmentSecretProvider) GetCurrentSecret

func (p EnvironmentSecretProvider) GetCurrentSecret() string

func (EnvironmentSecretProvider) GetDeprecatedReadonlySecret

func (p EnvironmentSecretProvider) GetDeprecatedReadonlySecret() string

func (EnvironmentSecretProvider) GetDeprecatedSecret

func (p EnvironmentSecretProvider) GetDeprecatedSecret() string

type EnvironmentSecretProviderSettingNames

type EnvironmentSecretProviderSettingNames struct {
	CurrentSecretHeaderName            string
	DeprecatedSecretHeaderName         string
	ReadonlySecretHeaderName           string
	DeprecatedReadonlySecretHeaderName string
}

type HeaderAuthProvider

type HeaderAuthProvider interface {
	Name() string
	Secret(r *http.Request) (string, bool)
}

type Options

type Options struct {
	ReadOnly                    bool
	FailureHandler              http.HandlerFunc
	SecretProvider              SecretProvider
	DeprecationExpirationPolicy DeprecationExpirationPolicy
	HeaderAuthProvider          HeaderAuthProvider
	// AllowedHTTPMethodsOverride allows customization of accepted HTTP methods.
	// A common use case is POST requests that actually perform read operations.
	AllowedHTTPMethodsOverride []string
}

func NewOptions

func NewOptions() Options

func NewReadonlyOptions

func NewReadonlyOptions() Options

type PermissionScope

type PermissionScope string

type SecretProvider

type SecretProvider interface {
	GetCurrentSecret() string
	GetDeprecatedSecret() string
	GetCurrentReadonlySecret() string
	GetDeprecatedReadonlySecret() string
}

type XApiKeyHeader

type XApiKeyHeader struct {
	HeaderAuthProvider
}

func (XApiKeyHeader) Name

func (h XApiKeyHeader) Name() string

func (XApiKeyHeader) Secret

func (h XApiKeyHeader) Secret(r *http.Request) (string, bool)

Jump to

Keyboard shortcuts

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