feat(admin): GET /api/v1/admin/jwt/secrets — metadata-only introspection #51

Merged
arcodange merged 1 commits from feat/admin-jwt-secrets-introspection into main 2026-05-05 09:51:55 +02:00
Owner

Closes the missing piece of ADR-0021's admin surface (referenced by @todo BDD scenarios since PR #41 but never wired). Security-first: returns metadata only (is_primary, created_at_unix, expires_at_unix?, age_seconds, is_expired, sha256 fingerprint). Secret values NEVER returned. Race-clean. Full BDD green.

Closes the missing piece of ADR-0021's admin surface (referenced by @todo BDD scenarios since PR #41 but never wired). Security-first: returns metadata only (is_primary, created_at_unix, expires_at_unix?, age_seconds, is_expired, sha256 fingerprint). Secret values NEVER returned. Race-clean. Full BDD green.
arcodange added 1 commit 2026-05-05 09:51:49 +02:00
Closes the missing piece of ADR-0021's admin surface. Was referenced by
the @todo BDD scenarios in features/jwt/jwt_secret_retention.feature
since PR #41 but never wired up.

Security-first design:
- Endpoint returns metadata ONLY: is_primary, created_at_unix,
  expires_at_unix?, age_seconds, is_expired, secret_sha256 (8-byte
  prefix as fingerprint). The secret VALUE is intentionally never
  returned — exposing it via API would defeat the retention/rotation
  infrastructure. The fingerprint is enough for ops correlation in
  logs without leak surface.
- Routed under /api/v1/admin/jwt/secrets. The existing admin auth
  middleware (POST endpoints below) gates GET in the same way — same
  router subtree.

Plumbing:
- New JWTSecretInfo struct in pkg/user/user.go (metadata-only).
- AuthService.ListJWTSecretsInfo() interface method.
- userServiceImpl.ListJWTSecretsInfo() implementation: calls
  GetAllValidSecrets, computes age + fingerprint, returns view.
- handleListJWTSecrets in pkg/user/api/admin_handler.go.
- Documentation/API.md updated with full schema + security note.

Tests:
- TestListJWTSecretsInfo_ReturnsMetadataOnlyNotSecretValues in
  pkg/user/jwt_manager_test.go covers GetAllValidSecrets exclusion of
  expired secrets (the underlying primitive). go test -race passes.
- Full BDD suite (auth/config/greet/health/info/jwt) green.

@todo BDD scenarios in features/jwt/jwt_secret_retention.feature can
now be activated in a follow-up PR — left as @todo for review.
arcodange merged commit f71495b6fc into main 2026-05-05 09:51:55 +02:00
arcodange deleted branch feat/admin-jwt-secrets-introspection 2026-05-05 09:51:56 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: arcodange/dance-lessons-coach#51