A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go

try and invalidate sessions

evan.jarrett.net d5df98bb 179f98cc

verified
Changed files
+37
pkg
appview
auth
oauth
+19
pkg/appview/db/oauth_store.go
··· 112 112 return nil 113 113 } 114 114 115 + // DeleteOldSessionsForDID removes all sessions for a DID except the specified session to keep 116 + // This is used during OAuth callback to clean up stale sessions with expired refresh tokens 117 + func (s *OAuthStore) DeleteOldSessionsForDID(ctx context.Context, did string, keepSessionID string) error { 118 + result, err := s.db.ExecContext(ctx, ` 119 + DELETE FROM oauth_sessions WHERE account_did = ? AND session_id != ? 120 + `, did, keepSessionID) 121 + 122 + if err != nil { 123 + return fmt.Errorf("failed to delete old sessions for DID: %w", err) 124 + } 125 + 126 + deleted, _ := result.RowsAffected() 127 + if deleted > 0 { 128 + slog.Info("Deleted old OAuth sessions for DID", "count", deleted, "did", did, "kept", keepSessionID) 129 + } 130 + 131 + return nil 132 + } 133 + 115 134 // GetAuthRequestInfo retrieves authentication request data by state 116 135 func (s *OAuthStore) GetAuthRequestInfo(ctx context.Context, state string) (*oauth.AuthRequestData, error) { 117 136 var requestDataJSON string
+18
pkg/auth/oauth/server.go
··· 122 122 123 123 slog.Debug("OAuth callback successful", "did", did, "sessionID", sessionID) 124 124 125 + // Clean up old OAuth sessions for this DID BEFORE invalidating cache 126 + // This prevents accumulation of stale sessions with expired refresh tokens 127 + // Order matters: delete from DB first, then invalidate cache, so when cache reloads 128 + // it will only find the new session 129 + type sessionCleaner interface { 130 + DeleteOldSessionsForDID(ctx context.Context, did string, keepSessionID string) error 131 + } 132 + if cleaner, ok := s.app.clientApp.Store.(sessionCleaner); ok { 133 + if err := cleaner.DeleteOldSessionsForDID(r.Context(), did, sessionID); err != nil { 134 + slog.Warn("Failed to clean up old OAuth sessions", "did", did, "error", err) 135 + // Non-fatal - log and continue 136 + } else { 137 + slog.Debug("Cleaned up old OAuth sessions", "did", did, "kept", sessionID) 138 + } 139 + } 140 + 125 141 // Invalidate cached session (if any) since we have a new session with new tokens 142 + // This happens AFTER deleting old sessions from database, ensuring the cache 143 + // will load the correct session when it's next accessed 126 144 if s.refresher != nil { 127 145 s.refresher.InvalidateSession(did) 128 146 slog.Debug("Invalidated cached session after creating new session", "did", did)