Skip to content

Skip authentication session expiration for realms without authentication sessions - #55016

Draft
ahus1 wants to merge 4 commits into
keycloak:mainfrom
ahus1:is-55015-skip-auth-session-expiration-empty-realm
Draft

ahus1 wants to merge 4 commits into
keycloak:mainfrom
ahus1:is-55015-skip-auth-session-expiration-empty-realm

Conversation

@ahus1

@ahus1 ahus1 commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Closes #55015

The expiration first looks for a single root authentication session of the realm with a one-row lookup, and only runs the per-bucket queries if one exists. The lookup is a prefix seek on IDX_ROOT_AUTH_SESSION_REALM, so no schema change is needed.

Decision: nothing is remembered between runs, which is the same pattern as for user sessions in #54886. A remembered "empty since T" mark would have depended on the clock and on node-local state. RealmAwareExpirationTask lets whichever node wins the per-realm check run the realm, so such a mark would only help while the same node keeps winning.

Trade-off: realms that do have sessions run one extra cheap query per run, 65 instead of 64. The saving is for realms without sessions, which go from 64 queries to 1. Authentication sessions are short-lived, so the benefit depends on how many realms are idle. This is an enhancement, not a regression, as JPA authentication sessions did not exist before 26.8.

Decision: the check runs before the per-realm claim in RealmAwareExpirationTask via a new ExpirationAction.hasWork (default true). A realm without sessions is not claimed, so its last-check row is no longer written every interval. In exchange, every node probes such a realm on each of its own runs, which is one cheap read per node and interval instead of one cluster-wide write. A skipped realm keeps its old last-check time, so the first run that finds sessions cleans it without waiting.

Assumption: the probe shares the transaction that reads the last-check row, which commits before any delete transaction starts, so it needs no separate transaction.

The integration tests run in the stateless test suite, as JPA authentication sessions need that feature. They check hasWork for an empty realm and for a realm whose session is created and then expired. ExpirationTaskTest covers that a realm without work is neither processed nor claimed.

…ion sessions

Closes keycloak#55015

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
…remembering empty realms

Closes keycloak#55015

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The expiration test can pass even when cleanup fails because the lookup deletes expired entities itself; it must query the entity directly to verify removal after an empty-realm probe.

1 open issue
What changed in this PR

This PR reduces database work during JPA authentication session expiration by checking whether a realm has sessions before querying all 64 buckets.

Changes:

  • Adds a one-row realm lookup using the existing index, reducing empty-realm expiration from 64 queries to one.
  • Keeps the check stateless, without caching results between runs.
  • Adds stateless-suite integration coverage for empty realms and expiration after session creation.
File Description
tests/​base/​src/​test/​java/​org/​keycloak/​tests/​suites/​StatelessTestSuite.java Registers the new expiration tests.
tests/​base/​src/​test/​java/​org/​keycloak/​tests/​model/​AuthenticationSessionExpirationQueryCountTest.java Tests query behavior and expiration after an empty-realm check.
model/​jpa/​src/​main/​java/​org/​keycloak/​authentication/​jpa/​RootAuthenticationSessionEntity.java Adds the realm session-existence query.
model/​jpa/​src/​main/​java/​org/​keycloak/​authentication/​jpa/​AuthenticationSessionExpirationAction.java Skips bucket queries when the realm has no sessions.

Review effort: Balanced

ahus1 and others added 2 commits November 12, 2026 12:49
Updated test to assert null on RootAuthenticationSessionEntity retrieval.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@gmx.net>
Closes keycloak#55015

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new test fails compilation due to a missing JpaConnectionProvider import, and the expiration change adds unnecessary transaction overhead for every due realm.

2 open issues
1 resolved since last review

Review effort: Balanced


import org.keycloak.authentication.jpa.AuthenticationSessionExpirationAction;
import org.keycloak.common.Profile;
import org.keycloak.common.util.Time;
Comment on lines +129 to +130
return KeycloakModelUtils.runJobInTransactionWithResult(factory, session ->
session.getProvider(ServerConfigStorageProvider.class).replace(key, lastCheck, Long.toString(currentTime)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Skip authentication session expiration for realms without authentication sessions

2 participants