✨ feat(admin): GET /api/v1/admin/jwt/secrets — metadata-only introspection (#51)
Co-authored-by: Gabriel Radureau <arcodange@gmail.com> Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
This commit was merged in pull request #51.
This commit is contained in:
@@ -2,6 +2,8 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -247,6 +249,31 @@ func (s *userServiceImpl) RemoveExpiredJWTSecrets() int {
|
||||
return s.secretManager.RemoveExpiredSecrets()
|
||||
}
|
||||
|
||||
// ListJWTSecretsInfo returns metadata about every currently-tracked JWT
|
||||
// secret WITHOUT exposing the secret values. Used by the admin
|
||||
// introspection endpoint and BDD tests verifying cleanup behavior.
|
||||
func (s *userServiceImpl) ListJWTSecretsInfo() []JWTSecretInfo {
|
||||
all := s.secretManager.GetAllValidSecrets()
|
||||
now := time.Now()
|
||||
out := make([]JWTSecretInfo, 0, len(all))
|
||||
for _, sec := range all {
|
||||
hash := sha256.Sum256([]byte(sec.Secret))
|
||||
info := JWTSecretInfo{
|
||||
IsPrimary: sec.IsPrimary,
|
||||
CreatedAtUnix: sec.CreatedAt.Unix(),
|
||||
AgeSeconds: int64(now.Sub(sec.CreatedAt).Seconds()),
|
||||
SecretSHA256: hex.EncodeToString(hash[:8]), // 16 hex chars = 8 bytes — fingerprint
|
||||
}
|
||||
if sec.ExpiresAt != nil {
|
||||
exp := sec.ExpiresAt.Unix()
|
||||
info.ExpiresAtUnix = &exp
|
||||
info.IsExpired = !sec.ExpiresAt.After(now)
|
||||
}
|
||||
out = append(out, info)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// UserExists checks if a user exists by username
|
||||
func (s *userServiceImpl) UserExists(ctx context.Context, username string) (bool, error) {
|
||||
return s.repo.UserExists(ctx, username)
|
||||
|
||||
Reference in New Issue
Block a user