Thread ctx through auth middleware DB lookups
The auth middleware's m.db.Preload + m.db.First calls were running without ctx, so on cache miss the resulting SQL queries appeared as orphan gorm.Query / gorm.Row spans in Jaeger. Now they nest under the parent HTTP request span like every other repo call. This was the last orphaned-SQL source on the request hot path. Combined with the seven service migrations, every authenticated API call now produces a fully-nested flame graph: HTTP → auth-token-lookup (cache hit) or HTTP → auth-token-SQL (cache miss) → service → service-SQL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -104,7 +104,7 @@ func (m *AuthMiddleware) TokenAuth() echo.MiddlewareFunc {
|
||||
}
|
||||
|
||||
// Cache miss - look up token in database
|
||||
user, authToken, err := m.getUserFromDatabaseWithToken(token)
|
||||
user, authToken, err := m.getUserFromDatabaseWithToken(c.Request().Context(), token)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Str("token", truncateToken(token)).Msg("Token authentication failed")
|
||||
return apperrors.Unauthorized("error.invalid_token")
|
||||
@@ -148,7 +148,7 @@ func (m *AuthMiddleware) OptionalTokenAuth() echo.MiddlewareFunc {
|
||||
}
|
||||
|
||||
// Try database
|
||||
user, authToken, err := m.getUserFromDatabaseWithToken(token)
|
||||
user, authToken, err := m.getUserFromDatabaseWithToken(c.Request().Context(), token)
|
||||
if err == nil && !m.isTokenExpired(authToken.Created) {
|
||||
m.cacheTokenInfo(c.Request().Context(), token, user.ID, authToken.Created)
|
||||
c.Set(AuthUserKey, user)
|
||||
@@ -224,7 +224,7 @@ func (m *AuthMiddleware) getUserFromCache(ctx context.Context, token string) (*m
|
||||
|
||||
// In-memory cache miss — fetch from database
|
||||
var user models.User
|
||||
if err := m.db.First(&user, userID).Error; err != nil {
|
||||
if err := m.db.WithContext(ctx).First(&user, userID).Error; err != nil {
|
||||
// User was deleted - invalidate caches
|
||||
m.cache.InvalidateAuthToken(ctx, token)
|
||||
return nil, err
|
||||
@@ -242,10 +242,11 @@ func (m *AuthMiddleware) getUserFromCache(ctx context.Context, token string) (*m
|
||||
}
|
||||
|
||||
// getUserFromDatabaseWithToken looks up the token in the database and returns
|
||||
// both the user and the auth token record (for expiry checking).
|
||||
func (m *AuthMiddleware) getUserFromDatabaseWithToken(token string) (*models.User, *models.AuthToken, error) {
|
||||
// both the user and the auth token record (for expiry checking). The ctx is
|
||||
// threaded into the GORM session so the SQL span attaches to the request trace.
|
||||
func (m *AuthMiddleware) getUserFromDatabaseWithToken(ctx context.Context, token string) (*models.User, *models.AuthToken, error) {
|
||||
var authToken models.AuthToken
|
||||
if err := m.db.Preload("User").Where("key = ?", token).First(&authToken).Error; err != nil {
|
||||
if err := m.db.WithContext(ctx).Preload("User").Where("key = ?", token).First(&authToken).Error; err != nil {
|
||||
return nil, nil, fmt.Errorf("token not found")
|
||||
}
|
||||
|
||||
@@ -262,8 +263,8 @@ func (m *AuthMiddleware) getUserFromDatabaseWithToken(token string) (*models.Use
|
||||
// getUserFromDatabase looks up the token in the database and caches the
|
||||
// resulting user record in memory.
|
||||
// Deprecated: Use getUserFromDatabaseWithToken for new code paths that need expiry checking.
|
||||
func (m *AuthMiddleware) getUserFromDatabase(token string) (*models.User, error) {
|
||||
user, _, err := m.getUserFromDatabaseWithToken(token)
|
||||
func (m *AuthMiddleware) getUserFromDatabase(ctx context.Context, token string) (*models.User, error) {
|
||||
user, _, err := m.getUserFromDatabaseWithToken(ctx, token)
|
||||
return user, err
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user