+19
pkg/appview/db/oauth_store.go
+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
+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)