Only cleanup orphan upstream authorization sessions

This includes sessions that were never completed, and sessions where
user_session was cleaned up. This is to avoid breaking features like
OIDC Backchannel Logout after 30 days.
This commit is contained in:
Quentin Gliech
2026-01-21 12:25:42 +01:00
parent 63f02c4dea
commit 39e417b461
5 changed files with 20 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n WITH to_delete AS (\n SELECT upstream_oauth_authorization_session_id\n FROM upstream_oauth_authorization_sessions\n WHERE ($1::uuid IS NULL OR upstream_oauth_authorization_session_id > $1)\n AND upstream_oauth_authorization_session_id <= $2\n ORDER BY upstream_oauth_authorization_session_id\n LIMIT $3\n )\n DELETE FROM upstream_oauth_authorization_sessions\n USING to_delete\n WHERE upstream_oauth_authorization_sessions.upstream_oauth_authorization_session_id = to_delete.upstream_oauth_authorization_session_id\n RETURNING upstream_oauth_authorization_sessions.upstream_oauth_authorization_session_id\n ",
"query": "\n WITH to_delete AS (\n SELECT upstream_oauth_authorization_session_id\n FROM upstream_oauth_authorization_sessions\n WHERE ($1::uuid IS NULL OR upstream_oauth_authorization_session_id > $1)\n AND upstream_oauth_authorization_session_id <= $2\n AND user_session_id IS NULL\n ORDER BY upstream_oauth_authorization_session_id\n LIMIT $3\n )\n DELETE FROM upstream_oauth_authorization_sessions\n USING to_delete\n WHERE upstream_oauth_authorization_sessions.upstream_oauth_authorization_session_id = to_delete.upstream_oauth_authorization_session_id\n RETURNING upstream_oauth_authorization_sessions.upstream_oauth_authorization_session_id\n ",
"describe": {
"columns": [
{
@@ -20,5 +20,5 @@
false
]
},
"hash": "da6baa340eedfce8e965c9f3baa90f21f2331c3881c082f0157752d241403b35"
"hash": "6db23fc9c39c2c7d9224d4e1233205f636568c990ccb05cf9208750ad1330b9b"
}

View File

@@ -0,0 +1,10 @@
-- no-transaction
-- Copyright 2026 Element Creations Ltd.
--
-- SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
-- Please see LICENSE files in the repository root for full details.
-- Add partial index for cleanup of orphaned upstream OAuth sessions
CREATE INDEX CONCURRENTLY IF NOT EXISTS upstream_oauth_authorization_sessions_orphaned
ON upstream_oauth_authorization_sessions (upstream_oauth_authorization_session_id)
WHERE user_session_id IS NULL;

View File

@@ -580,7 +580,7 @@ impl UpstreamOAuthSessionRepository for PgUpstreamOAuthSessionRepository<'_> {
),
err,
)]
async fn cleanup(
async fn cleanup_orphaned(
&mut self,
since: Option<Ulid>,
until: Ulid,
@@ -596,6 +596,7 @@ impl UpstreamOAuthSessionRepository for PgUpstreamOAuthSessionRepository<'_> {
FROM upstream_oauth_authorization_sessions
WHERE ($1::uuid IS NULL OR upstream_oauth_authorization_session_id > $1)
AND upstream_oauth_authorization_session_id <= $2
AND user_session_id IS NULL
ORDER BY upstream_oauth_authorization_session_id
LIMIT $3
)

View File

@@ -211,9 +211,11 @@ pub trait UpstreamOAuthSessionRepository: Send + Sync {
async fn count(&mut self, filter: UpstreamOAuthSessionFilter<'_>)
-> Result<usize, Self::Error>;
/// Cleanup old authorization sessions
/// Cleanup old authorization sessions that are not linked to a user session
///
/// This will delete sessions with IDs up to and including `until`.
/// Authorization sessions with a user session linked must be kept around to
/// avoid breaking features like OIDC Backchannel Logout.
///
/// Returns the number of sessions deleted and the cursor for the next batch
///
@@ -227,7 +229,7 @@ pub trait UpstreamOAuthSessionRepository: Send + Sync {
/// # Errors
///
/// Returns [`Self::Error`] if the underlying repository fails
async fn cleanup(
async fn cleanup_orphaned(
&mut self,
since: Option<Ulid>,
until: Ulid,
@@ -277,7 +279,7 @@ repository_impl!(UpstreamOAuthSessionRepository:
async fn count(&mut self, filter: UpstreamOAuthSessionFilter<'_>) -> Result<usize, Self::Error>;
async fn cleanup(
async fn cleanup_orphaned(
&mut self,
since: Option<Ulid>,
until: Ulid,

View File

@@ -345,7 +345,7 @@ impl RunnableJob for CleanupUpstreamOAuthSessionsJob {
let mut repo = state.repository().await.map_err(JobError::retry)?;
let (count, cursor) = repo
.upstream_oauth_session()
.cleanup(since, until, BATCH_SIZE)
.cleanup_orphaned(since, until, BATCH_SIZE)
.await
.map_err(JobError::retry)?;
repo.save().await.map_err(JobError::retry)?;