package auth import ( "crypto/rand" "encoding/hex" "errors" "sync" "time" ) var ( ErrInvalidToken = errors.New("invalid token") ErrTokenExpired = errors.New("token expired") ) // TokenInfo holds information about a token type TokenInfo struct { Token string UserID string Permissions []string CreatedAt time.Time ExpiresAt *time.Time Revoked bool } // TokenManager manages authentication tokens type TokenManager struct { tokens map[string]*TokenInfo mu sync.RWMutex } // NewTokenManager creates a new token manager func NewTokenManager() *TokenManager { return &TokenManager{ tokens: make(map[string]*TokenInfo), } } // GenerateToken generates a new random token func GenerateToken() (string, error) { b := make([]byte, 32) if _, err := rand.Read(b); err != nil { return "", err } return hex.EncodeToString(b), nil } // AddToken adds a new token to the manager func (tm *TokenManager) AddToken(token string, userID string, permissions []string) { tm.mu.Lock() defer tm.mu.Unlock() tm.tokens[token] = &TokenInfo{ Token: token, UserID: userID, Permissions: permissions, CreatedAt: time.Now(), ExpiresAt: nil, // No expiration for MVP Revoked: false, } } // ValidateToken validates a token and returns its info func (tm *TokenManager) ValidateToken(token string) (*TokenInfo, error) { tm.mu.RLock() defer tm.mu.RUnlock() info, exists := tm.tokens[token] if !exists { return nil, ErrInvalidToken } if info.Revoked { return nil, ErrInvalidToken } if info.ExpiresAt != nil && time.Now().After(*info.ExpiresAt) { return nil, ErrTokenExpired } return info, nil } // RevokeToken revokes a token func (tm *TokenManager) RevokeToken(token string) error { tm.mu.Lock() defer tm.mu.Unlock() info, exists := tm.tokens[token] if !exists { return ErrInvalidToken } info.Revoked = true return nil } // ListTokens returns a list of all tokens (excluding sensitive data) func (tm *TokenManager) ListTokens() []*TokenInfo { tm.mu.RLock() defer tm.mu.RUnlock() var result []*TokenInfo for _, info := range tm.tokens { result = append(result, info) } return result } // HasPermission checks if a token has a specific permission func (tm *TokenManager) HasPermission(token string, permission string) (bool, error) { info, err := tm.ValidateToken(token) if err != nil { return false, err } // Admin has all permissions for _, p := range info.Permissions { if p == "admin" || p == permission { return true, nil } } return false, nil }