SIGN IN SIGN UP

fix(auth): reconcile a group set the user moved past instead of serving it from cache (LE-2099) (#14594)

* fix(auth): reconcile a group set the user moved past instead of serving it from cache (LE-2099)

The LE-2109 reconciliation cache was keyed by the exact directory state it
verified, and entries were only ever added and aged out. A group set that
was cached, then changed, then changed back still matched its earlier entry,
so a promotion followed by an IdP revocation kept the promoted role until
the stale entry expired - up to EXTERNAL_AUTH_GROUP_RECONCILE_INTERVAL_SECONDS
on the replica holding it, and the authorization plugin was never consulted
in that window. QA reproduced it as [devs] -> [admins, devs] -> [devs]:
the last step served admin for 60s.

The cache now holds one entry per user: the last state a confirming pass
verified. A request is skipped only when that entry is fresh and carries the
same state, so any claim that differs from the last reconciled state misses
by construction, including one that was itself cached earlier.

Two more rules cover overlapping passes for one user (an old and a new token
in flight together): a miss drops the user's entry and hands the pass a
ticket that only the latest pass holds, and a pass that changed the stored
state invalidates - dropping the entry and revoking the outstanding ticket -
so a concurrent no-op pass that verified the previous state can neither be
served nor remembered after the change landed.

The settings description already promised "a group set that differs from the
last reconciled one always reconciles immediately"; the implementation now
matches it.

* docs(auth): spell out the one-slot-per-user trade-off in the reconcile cache
E
Eric Hare committed
4454221b37b585b09bfb411fabf68e6b105143b4
Parent: 7ed4de4
Committed by GitHub <noreply@github.com> on 8/16/2026, 1:46:58 PM