Files
noema/internal/auth/token.go
T
Andy Dixon a002a2c100 feat: add authentication, audit log, HTTP API and base web UI
Phase 1 foundation. Local auth per ADR-0006: Argon2id passwords, opaque
hashed session tokens with idle/absolute expiry, CSRF token plus Origin
check on cookie sessions, per-IP token bucket and per-account exponential
lockout, three roles enforced by middleware, personal API tokens for
noemactl. Audit log writer used by every admin mutation.

API: request ids, panic recovery, strict CSP and security headers, body
limits, single JSON error envelope, health/ready/status, users, sessions,
tokens, audit, token-protected /metrics.

UI: embedded html/template pages (login, first-run setup, dashboard,
system, users, account, audit, interpretation boundary), light/dark
theme, dependency-free app.js with CSRF-aware fetch and SSE helper.

Binaries: noemad with graceful shutdown, migrations at start, bootstrap
admin from environment, supervised background tasks; noemactl with
status, migrate, user create and meaningful exit codes.
2026-06-15 20:22:19 +01:00

24 lines
578 B
Go

package auth
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
)
// newToken returns a 256-bit random token in URL-safe base64 and its SHA-256,
// which is what gets stored. A database leak therefore does not leak sessions.
func newToken() (token string, hash []byte) {
b := make([]byte, 32)
if _, err := rand.Read(b); err != nil {
panic("auth: crypto/rand unavailable: " + err.Error())
}
token = base64.RawURLEncoding.EncodeToString(b)
return token, hashToken(token)
}
func hashToken(token string) []byte {
h := sha256.Sum256([]byte(token))
return h[:]
}