apikey

package
v1.11.7 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package apikey issues and verifies opaque API keys for authcore.

What it is for

API keys authenticate machines — a CLI, a service, a webhook caller — where a username/password or a short-lived JWT does not fit. authcore generates a high-entropy opaque key, returns a hash for you to store, and verifies a presented key against that hash in constant time. The library never stores anything; you own the database.

Key shape

	<prefix>_<id>_<secret>

  - prefix — a short fixed tag (default "ak") so a leaked key is recognisable
    in logs and can be scanned for.
  - id     — a random public identifier. Store it in plaintext and use it as
    the database lookup key, so verification is an O(1) row fetch, not a scan.
  - secret — 256 bits of CSPRNG output, hex-encoded. Only its keyed hash is
    stored.

Storage model

The key is high-entropy random, so it is hashed with keyed HMAC-SHA256 (fast, constant-time-verifiable, peppered with the library's managed secret) rather than a slow password hash — a per-request API call must not pay Argon2id cost, and a 256-bit random key has no need of it.

auth, _   := authcore.New(authcore.DefaultConfig())
keyMod, _ := apikey.New(auth)

// Issue — show key.Key to the user ONCE; store key.ID and key.Hash.
key, _ := keyMod.Generate()
db.StoreAPIKey(key.ID, key.Hash, userID)

// Verify — extract the id, fetch the row, compare in constant time.
id, err := keyMod.ParseID(presented)
if err != nil { return http.StatusUnauthorized }
row, err := db.FindAPIKey(id)
if err != nil || !keyMod.Verify(presented, row.Hash) { return http.StatusUnauthorized }

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidConfig is returned by New when the provided Config fails
	// validation (e.g. an empty or malformed Prefix).
	//
	// Safety: INTERNAL — a startup/programming error. Treat as a 500.
	ErrInvalidConfig = errors.New("apikey: invalid configuration")

	// ErrInvalidKey is returned by ParseID when the presented key is not a
	// well-formed key for this module (wrong prefix, structure, or id).
	//
	// Safety: INTERNAL — return a generic "unauthorized" to the client; never
	// echo back why the key was rejected.
	ErrInvalidKey = errors.New("apikey: malformed key")
)

Sentinel errors returned by the apikey package. Use errors.Is to check for these in calling code.

Functions

This section is empty.

Types

type APIKey

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

APIKey is the opaque API-key module.

Construct one instance at application startup using New and share it across goroutines. APIKey is safe for concurrent use after construction.

func New

func New(p authcore.Provider, cfg ...Config) (*APIKey, error)

New creates an APIKey module.

cfg is optional — omit it for the default key prefix ("ak"):

keyMod, err := apikey.New(auth)
keyMod, err := apikey.New(auth, apikey.Config{Prefix: "svc"})

func (*APIKey) Generate

func (a *APIKey) Generate() (*GeneratedKey, error)

Generate mints a new opaque API key. The id and secret are independent CSPRNG draws; the returned Hash is what you store.

func (*APIKey) Hash

func (a *APIKey) Hash(key string) string

Hash returns the keyed HMAC-SHA256 digest of key. Use it to recompute the stored value (it matches GeneratedKey.Hash for the same key).

func (*APIKey) Name

func (a *APIKey) Name() string

Name returns the module's unique identifier. It implements authcore.Module.

func (*APIKey) ParseID

func (a *APIKey) ParseID(key string) (string, error)

ParseID extracts the public identifier from a presented key without verifying it, so you can fetch the stored hash before the constant-time comparison.

It returns ErrInvalidKey if key is not a well-formed key for this module (wrong prefix, wrong structure, or a malformed id).

func (*APIKey) Verify

func (a *APIKey) Verify(key, storedHash string) bool

Verify reports whether key matches storedHash, comparing in constant time to prevent timing attacks.

type Config

type Config struct {
	// Prefix is the fixed tag at the start of every key (e.g. "ak" -> "ak_...").
	// Pick something short and product-specific so a leaked key is recognisable
	// in logs and secret scanners. Must be 1–16 lowercase letters or digits and
	// must not contain "_" (the field separator).
	//
	// Defaults to "ak".
	Prefix string
}

Config holds the apikey module configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with safe defaults.

type GeneratedKey

type GeneratedKey struct {
	// Key is the full opaque API key to hand to the caller, once.
	Key string
	// ID is the public identifier embedded in Key. Store it and use it to look
	// up the stored hash on verification.
	ID string
	// Hash is the keyed HMAC-SHA256 digest of Key. Store only this.
	Hash string
}

GeneratedKey is the result of Generate.

Show Key to the user exactly once — it is never recoverable afterwards. Persist ID (plaintext, the lookup key) and Hash (never the raw key).

Jump to

Keyboard shortcuts

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