apikey

package module
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 13 Imported by: 0

README

Station Mangaer: apikey package

API keys and logbook identity — High‑level design

Purpose

  • Authenticate and authorise QSO uploads per logbook.
  • Keep clients simple: each logbook has one full API key and an opaque uid.
  • Minimise leakage: the server stores only a digest of the secret, never the full key.

Identifiers

  • uid: immutable, opaque ID for each logbook used externally by clients and APIs.
  • logbook_id: internal sequential PK used for joins; resolved from uid server‑side.

API key model

  • Full key format: prefix.secretHex.
  • prefix: independent random hex string (e.g., 12–16 chars) used for indexed lookup; not derived from secretHex.
  • secretHex: 64 hex chars (32 random bytes) shown to the client once.
  • digest: server‑stored hash of secretHex (e.g., SHA‑512 hex) or HMAC(secretHex, PEPPER). Only the digest is stored.

Workflow (high level)

  1. User creates a logbook in the desktop app.
  2. Desktop app registers the logbook with the server.
  3. Server generates an API key and a logbook uid and returns both to the client over TLS (only once).
  4. Client stores the logbook metadata, full API key, and uid locally.
  5. Client uploads QSOs with Authorization: ApiKey <prefix>.<secretHex> and the logbook uid. Server verifies and enforces integrity rules.

Server responsibilities

  • Key generation: create a 32‑byte random secret, generate an independent random prefix, compute and store a digest (optionally HMAC with a server‑side pepper), associate with the logbook, and return only the full key and uid once.
  • Key validation: parse prefix/secretHex, resolve uid to logbook, find an active key by prefix, recompute digest and compare in constant time, update usage metrics on success.
  • Integrity on QSO writes: enforce that the logging station callsign equals the logbook’s callsign (the contacted station callsign is unconstrained).
  • Rotation/revocation: support revocation; policy may enforce at most one active key per logbook.

Client responsibilities

  • Store the full API key and uid locally with the logbook. Do not log the full key. Consider encrypting at rest.
  • Include Authorization: ApiKey <prefix>.<secretHex> and the logbook uid on write requests.
  • Replace the stored key when rotated.

Security notes

  • Use TLS end‑to‑end.
  • Prefer uid as the external logbook identifier.
  • Consider HMAC with a server‑side pepper to harden digest storage; keep the pepper out of the database.

This document is intentionally high‑level; SQL schemas and code are documented elsewhere.

Documentation

Index

Constants

View Source
const (
	// DefaultSecretBytes is the number of random bytes used for the secret part
	DefaultSecretBytes = 20
	// MaxPrefixLen is the maximum prefix length allowed (matches DB varchar(16))
	MaxPrefixLen = 16
	// SecretSymbolLen is the exact number of non-dash symbols required in a
	// valid user-facing secret. This is enforced in isValidSecret.
	SecretSymbolLen = DefaultSecretBytes
)

Variables

This section is empty.

Functions

func GenerateApiKey

func GenerateApiKey(prefixLen int) (fullKey, prefix, hash string, err error)

GenerateApiKey creates a new API key.

It returns only text-safe, UTF-8 strings suitable for storage in database TEXT/VARCHAR columns:

  • fullKey: "<prefix>_<secret>", where prefix is lowercase hex and secret is an upper-case user-friendly Base32-like string (possibly with dashes), safe for copy/paste by end users.
  • prefix: a lowercase hex string of length prefixLen (or MaxPrefixLen when prefixLen is out of range).
  • hash: the SHA-512 digest of the secret, hex-encoded.

The returned secret is the user-facing sensitive value and is embedded in fullKey after the underscore. No raw binary data is ever returned to callers. If prefixLen is <=0 or > MaxPrefixLen it will be clamped to MaxPrefixLen.

func GenerateBootstrap

func GenerateBootstrap() (plain, hash string, expires time.Time, err error)

GenerateBootstrap creates a new one-off bootstrap secret suitable for securely provisioning a client or account.

It returns only text-safe, UTF-8 strings:

  • plain: a 64-character hex-encoded bootstrap secret that must be sent once to the client (or used in the initial bootstrap request). This value is **not** stored server-side and must be treated as sensitive.
  • hash: a persistent representation of the secret for storage in the database. The format is: <salt-hex><colonString><argon2id-hash-hex> where:
  • salt-hex is a 16-byte random salt, hex-encoded.
  • argon2id-hash-hex is the Argon2ID-derived key of sha256(secret) with the generated salt, using parameters time=1, memory=64*1024 KiB, threads=4, keyLen=32. This value is suitable for storage in TEXT/VARCHAR columns.
  • expires: a UTC timestamp set to 24 hours from the time of generation. Callers should persist this value and refuse bootstrap tokens that are presented after this time.
  • err: a non-nil error if a cryptographically secure random value could not be generated for either the secret or the salt.

The generated secret and salt use crypto/rand for randomness. On error, plain, hash, and expires are left at their zero values and err is set.

func HashApiKeySecret

func HashApiKeySecret(secret string) string

HashApiKeySecret returns the SHA-512 hex digest of the user-friendly secret string. The returned value is a lowercase hex-encoded string, safe for storage in TEXT/VARCHAR columns.

func HashPassword

func HashPassword(password string) (string, error)

HashPassword derives an Argon2id hash for the provided password and returns a PHC-formatted string:

$argon2id$v=19$m=<mem>,t=<time>,p=<par>$<saltB64>$<hashB64>

The returned string contains only ASCII characters and is safe for storage in TEXT/VARCHAR columns.

func ParseApiKey

func ParseApiKey(fullKey string) (prefix, secret string, err error)

ParseApiKey splits a fullKey into prefix and secret. fullKey is expected to be "prefix_secret" where both parts are text-safe UTF-8 strings. The returned secret is the user-friendly secret portion as produced by GenerateApiKey and must be treated as sensitive.

func ValidateApiKey

func ValidateApiKey(fullKey, storedHash string) (bool, error)

ValidateApiKey checks that fullKey (API Key) matches the provided storedHash (hex SHA-512 of the user-friendly secret). It returns true when they match; comparison is done in constant time. storedHash is expected to be the result of HashApiKeySecret and is always a hex-encoded string.

func ValidateBootstrap

func ValidateBootstrap(plain, stored string) (bool, error)

ValidateBootstrap checks whether the given plaintext bootstrap token matches the stored Argon2ID hash produced by GenerateBootstrap.

  • plain must be the 64-character hex string previously returned from GenerateBootstrap.
  • stored must have the format "<salt-hex><colonString><argon2id-hash-hex>" as produced by GenerateBootstrap and is assumed to have been stored in a TEXT/VARCHAR column.

func VerifyPassword

func VerifyPassword(phc, password string) (bool, error)

VerifyPassword checks a password against a PHC-formatted Argon2id hash. Returns true if it matches, false otherwise. The phc parameter is expected to be the encoded string returned from HashPassword.

Types

This section is empty.

Jump to

Keyboard shortcuts

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