ValidateAuthToken validates an auth token against persistent storage. It includes a short-term in-memory cache to prevent
(ctx context.Context, token string)
| 274 | // ValidateAuthToken validates an auth token against persistent storage. |
| 275 | // It includes a short-term in-memory cache to prevent |
| 276 | func (s *Service) ValidateAuthToken(ctx context.Context, token string) (AuthToken, error) { |
| 277 | // Wrapper type for cache entries |
| 278 | type authCacheEntry struct { |
| 279 | token AuthToken |
| 280 | err error |
| 281 | time time.Time |
| 282 | } |
| 283 | |
| 284 | // Use a secure hash of the token string as the cache key to avoid storing raw tokens in memory. |
| 285 | tokenHash := sha256.Sum256([]byte(token)) |
| 286 | cacheKey := fmt.Sprintf("%x", tokenHash[:]) |
| 287 | |
| 288 | // Try cache |
| 289 | val, ok := s.authCache.Get(cacheKey) |
| 290 | if ok { |
| 291 | entry, ok := val.(authCacheEntry) |
| 292 | if ok && time.Since(entry.time) < _authCacheTTL { |
| 293 | return entry.token, entry.err |
| 294 | } |
| 295 | // Even if its expired, we don't remove it from the cache as it'll be replaced below. |
| 296 | } |
| 297 | |
| 298 | // Not cached or expired, validate |
| 299 | authTok, err := s.validateAuthTokenUncached(ctx, token) |
| 300 | if err != nil && errors.Is(err, ctx.Err()) { // Only exit early for context errors |
| 301 | return nil, err |
| 302 | } |
| 303 | |
| 304 | // Cache the validation result (both token and error) |
| 305 | s.authCache.Add(cacheKey, authCacheEntry{ |
| 306 | token: authTok, |
| 307 | err: err, |
| 308 | time: time.Now(), |
| 309 | }) |
| 310 | |
| 311 | return authTok, err |
| 312 | } |
| 313 | |
| 314 | func (s *Service) validateAuthTokenUncached(ctx context.Context, token string) (AuthToken, error) { |
| 315 | parsed, err := authtoken.FromString(token) |
no test coverage detected