diff --git a/server/internal/auth/middleware.go b/server/internal/auth/middleware.go index e17acc3..151e602 100644 --- a/server/internal/auth/middleware.go +++ b/server/internal/auth/middleware.go @@ -135,9 +135,13 @@ func sessionFromToken(c *gin.Context) (*Session, bool) { tok, err := services.ResolveAPIToken(raw) if errors.Is(err, services.ErrTokenExpired) { // Recorded rather than only refused: an expired token still being - // presented is how a forgotten CI job becomes visible. - services.LogEvent(tok.InstanceID, "token.expired_use", tok.Name, "", "", - fmt.Sprintf("expired token '%s' was used", tok.Name)) + // presented is how a forgotten CI job becomes visible. Throttled to + // once per token per minute, or a looping job writes an unbounded + // stream of audit rows instead of one. + if services.ShouldLogExpiredTokenUse(tok.TokenID) { + services.LogEvent(tok.InstanceID, "token.expired_use", tok.Name, "", "", + fmt.Sprintf("expired token '%s' was used", tok.Name)) + } c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "token expired", "code": "token_expired"}) return nil, false }