feat: add Personal Access Tokens (PAT) for CLI/API authentication

RO
2mo ago
+4514-16

Summary

Introduces a Personal Access Token (PAT) system as a replacement for the OIDC CLI secret, providing named, expiring, auditable tokens for CLI/API authentication.

  • Backend: New personal_access_token table, full CRUD API under /api/v2.0/users/{id}/personal_access_tokens, PBKDF2-SHA256 hashing with salt, security middleware integration for HTTP Basic Auth
  • Migration: Existing OIDC CLI secrets automatically migrated to legacy PAT records on startup — no user action required
  • Portal: Standalone "Personal Access Tokens" modal (opened from the user dropdown menu, alongside "User Profile" and "Preferences") for create/list/delete/enable/disable/refresh with copy-to-clipboard support. The CLI secret section in the User Profile modal is unchanged; PAT management was not folded into that modal since its own PAT-management UI had grown too large to sit comfortably as a tab there.
  • Auth: Token format hbr_pat_<32-char-random>, full user permissions (v1), configurable TTL or never-expire (-1), last_used_at audit trail

Token format

hbr_pat_<32-char-random>

Storage: PBKDF2-SHA256 hash with salt (consistent with robot accounts)

Related

Test plan

  • Create a PAT via the UI and verify the token is displayed once
  • Use the PAT for docker login — login should succeed
  • Verify existing OIDC CLI secrets are auto-migrated to PATs on startup
  • Delete/disable a PAT and verify it no longer authenticates
  • Refresh a PAT secret and verify the old secret no longer authenticates
  • Verify expired PATs are rejected
  • Unit tests: src/pkg/pat/, src/controller/pat/, src/server/middleware/security/pat_test.go