fix(backend): make access tokens revocable via session validation

The auth middleware trusted any unexpired, well-signed access token, so
logout, session termination and admin blocks had no effect until the
15-minute token expired. The middleware now validates that the token's
session is still active on every request (SessionRepo.GetByID), and
blocking a user deactivates all of their sessions, immediately revoking
their outstanding access tokens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 14:09:25 +03:00
parent fa2acca858
commit 4645107ea1
7 changed files with 47 additions and 11 deletions
+10 -5
View File
@@ -13,13 +13,14 @@ import (
// UserService handles user CRUD and profile management.
type UserService struct {
users port.UserRepo
audit *AuditService
users port.UserRepo
sessions port.SessionRepo
audit *AuditService
}
// NewUserService creates a UserService.
func NewUserService(users port.UserRepo, audit *AuditService) *UserService {
return &UserService{users: users, audit: audit}
func NewUserService(users port.UserRepo, sessions port.SessionRepo, audit *AuditService) *UserService {
return &UserService{users: users, sessions: sessions, audit: audit}
}
// EnsureAdmin creates the initial administrator account if it does not already
@@ -166,11 +167,15 @@ func (s *UserService) UpdateAdmin(ctx context.Context, id int16, p UpdateAdminPa
return nil, err
}
// Log block/unblock specifically.
// Log block/unblock specifically, and revoke all sessions on block so the
// user's outstanding access tokens stop working immediately.
if p.IsBlocked != nil {
action := "user_unblock"
if *p.IsBlocked {
action = "user_block"
if err := s.sessions.DeleteByUserID(ctx, id); err != nil {
return nil, fmt.Errorf("UserService.UpdateAdmin revoke sessions: %w", err)
}
}
_ = s.audit.Log(ctx, action, nil, nil, map[string]any{"target_user_id": id})
}