Files
auth/CLAUDE.md
T
argoyleandClaude Opus 5.5 475b0ffc71
auth / test (push) Skipped
auth / vulnerabilities (push) Skipped
pre-commit / pre-commit (push) Skipped
auth / coverage-baseline (pull_request) Skipped
auth / test (pull_request) Successful in 43s
auth / vulnerabilities (pull_request) Successful in 35s
pre-commit / pre-commit (pull_request) Successful in 3m9s
feat: move module path to git.unbound.se
The module is now git.unbound.se/shiny/auth. The API is unchanged. Tags up to v0.1.1 declare gitea.unbound.se/shiny/auth and stay resolvable through that alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kko4x3MYEcWMMdkx12WpBa
2026-10-17 19:54:52 +02:00

2.2 KiB

auth

Shared Go library with authentication primitives for all Shiny backend services.

Shared Documentation

@../docs/claude/architecture.md @../docs/claude/go-services.md @../docs/claude/conventions.md

Library Information

Purpose

Single home for the user-header auth and secret-startup-guard code that was previously byte-identical-copied into every backend (the auth package and cmd/service/secrets_guard.go). Enforces ADR-0005 (HMAC-signed user header, keyless fail-open only in acctest) and ADR-0006 (fail closed when required secrets are missing in staging/production).

Usage

import "git.unbound.se/shiny/auth"

// Fail closed on missing deployed secrets before serving (ADR-0005/0006).
if missing := auth.MissingDeployedSecrets(environment, map[string]string{
    "USER_SIGNING_KEY":  cfg.UserSigningKey,
    "INTERNAL_API_KEY":  cfg.InternalAPIKey,
}); len(missing) > 0 {
    log.Fatalf("refusing to start: missing secrets in %s: %v", environment, missing)
}

// Verify the gateway's signed user header and inject *User into the context.
handler = auth.UserMiddleware([]byte(cfg.UserSigningKey))(handler)

// Read the authenticated user downstream.
user := auth.FromContext(ctx)
if user.HasRole("admin") { /* ... */ }

Exported API

  • UserMiddleware(signingKey []byte) — HTTP middleware verifying the HMAC-signed user header; injects *User into the request context.
  • FromContext(ctx) *User, User.HasRole(...) bool, ContextKey/UserKey.
  • MissingDeployedSecrets(environment string, secrets map[string]string) []string — returns the sorted names of secrets that are empty in staging/production (nil for any other environment, e.g. development/acctest).

Conventions

Standard Shiny library scaffolding: gofumpt/goimports -local, golangci-lint, gitleaks and conventional-commit checks via pre-commit; coverage-regression gate in CI (.testcoverage.yml); releases auto-tagged from conventional commits by the shared Release workflow. Bump the consuming services' go.mod after a release. A breaking change to the signed-header or secret-guard contract is a cross-service change — see ADR-0005/0006 before changing it.