skip to content

A back-channel logout notice from the identity provider is delivered at least once — what must your handler do so a repeat is harmless?

level: seniorimportance: should knowfreq 36%

answer

  1. delivery is at-least-once
  2. aim at an end state, not an event
  3. already signed out is a success
  4. dedupe suppresses side effects, not correctness
  5. the window sits below the delete

basics

~20 s

Write the handler to converge on an end state rather than to process an event: resolve the notice to a set of local sessions, delete conditionally, and answer success when there is nothing left to delete. A repeat then changes nothing.

solid answer

~40 s

Delivery is at-least-once, so the same notice can arrive twice — a retry after your handler answered slowly, or a provider that re-fans-out on every attempt. Make the handler's effect an end state, "these sessions no longer exist", reached by a conditional delete over the resolved set; a second run deletes nothing and still succeeds. A notice for a researcher who is already signed out is a **success**, not an error: failing it only makes the provider retry harder and turns an ordinary delivery into an alert. Replay detection on the notification's own identifier (`jti`) is OPTIONAL in the specification, so a short dedupe window is your decision — it buys suppressed duplicate audit rows and suppressed repeat side effects, not correctness, and correctness must not depend on it.

code

pseudocode · 13 lines
pseudocode
on logoutNotice(notice):                          # delivery is at-least-once
    verifyItCameFromTheProvider(notice)

    targets = sessionsNamedBy(notice)             # 0..n rows; 0 is a normal result
    for session in targets:
        if sessions.deleteIfPresent(session.sessionId):
            audit("session ended by provider notice", session.sessionId)

    # the window guards only the work that is NOT safe to repeat
    if dedupe.putIfAbsent(notice.id, ttl = 10 minutes):
        notifyOpenTabsToStopPolling(targets)

    return success                                # nothing left to end is the goal state

go deeper

for a junior

Recall that this notice arrives at a server endpoint rather than in the user's browser, and that receiving the very same one twice must not turn into an error.

for a middle

Explain why a conditional delete over the resolved session set is naturally repeatable, and why 'already signed out' is a successful outcome rather than a missing-record failure.

for a senior

Show the operational reasoning: retries caused by your own slow handler, duplicate audit rows and repeat side effects as the real cost of replay, and an explicit decision about what a sign-out deliberately leaves standing.

for a principal

Weigh what the service can honestly promise when a notice is never delivered or never executed, and whether that residual is covered by shortening local session lifetimes or simply accepted, documented and reported as such.

## At-least-once is the contract, not a provider defect A reference manager that has registered a server endpoint for logout notices is receiving a delivery, and deliveries repeat. The provider cannot distinguish "my request timed out" from "the request arrived and the response was lost", so when your handler takes too long, or a network hop drops the response, the only safe thing the provider can do is send it again. Several ordinary situations produce a repeat: - **A retry after a slow handler** — the commonest by far, and it means the duplicate usually arrives while the original is still running. - **A re-fan-out**, where the provider re-notifies every registered application on a later attempt because one of them failed. - **A second notice of a different shape**: one naming a specific sign-in, one naming only the researcher, seconds apart. - **Your own replay**, when an operator re-drives a stored notice after fixing a bug in the handler. None of these is anomalous, so none of them may be modelled as an error. The design question is not "how do I stop duplicates" — you cannot — but "what makes a duplicate a non-event". ## Converge on an end state The answer is to stop treating the notice as an event to process and start treating it as an assertion of a desired state: *the sessions this notice names must not exist*. Written that way the handler is naturally repeatable: 1. **Verify the notice came from the provider** you expect. Everything below assumes a verified notice. 2. **Resolve it to a set** of local session identifiers through the index built at login. An empty set is a normal result. 3. **Delete conditionally** — delete-if-present, one row at a time, and let the store tell you whether the row was actually there. 4. **Record only the runs that changed something.** The delete that found nothing is not an incident and should not read like one in the audit trail. 5. **Answer success.** Nothing left to end is the goal state, and a success also stops the provider retrying a delivery that has already achieved its purpose. The second delivery walks the same five steps, finds the rows already gone, and returns the same answer. That is the whole of replay safety, and it is free. ## What a replay window actually buys The specification makes the replay check on the notification's own identifier OPTIONAL, which is a hint about what it is for. It is not what makes you correct; convergence already did that. It is what stops the *non-idempotent* work hanging off the handler from repeating. | | No dedupe window | Short window keyed on `jti` | |---|---|---| | Correctness under replay | already safe, by convergence | unchanged — no better | | Duplicate audit rows | yes, one per delivery | suppressed | | Repeat downstream side effects | yes | suppressed | | Cost | none | a keyed write per notice, plus a store to keep it in | | If the store is lost | nothing changes | duplicates are readmitted, and that is all | Two consequences follow. Size the window to the provider's retry horizon — minutes, not days. And never let the window sit *above* the deletion: if a duplicate skips the whole body because an earlier delivery claimed the identifier and then failed part-way, the notice is recorded as handled and the sessions are still live. The window belongs around the side effects, below the work that must always run. ## What ends, and what deliberately survives A logout notice is a statement about **sessions**, and it is worth deciding explicitly — rather than by omission — what else it touches. A standing grant your service holds to import from a journal repository on the researcher's behalf, obtained with `offline_access` so a nightly job can run while nobody is signed in, is not ended by the researcher signing out at their institution. It normally survives, and it should: a background import that dies because someone closed a browser at a library terminal is a bug, not a security win. If your product wants the opposite, that is a deliberate choice to write down, because nothing in the notice says it. ## The gap you cannot close from either side Where the notice is delivered by loading a hidden frame in the researcher's browser, the browser may simply never execute it — the tab was closed, third-party cookies were blocked, the frame was stopped. **No request arrives at your server**, and a request that never arrives is indistinguishable from a researcher who never signed out. You cannot detect it, and neither can the provider observe your handling. Treat unreached sessions as an accepted residual and state it plainly, rather than reporting logout as complete; the only lever you actually hold is how long an unreached local session is allowed to live.

  • What does a short dedupe window keyed on the notification's identifier actually buy you?
    Suppression, not correctness. A converging handler is already replay-safe; the window stops duplicate audit rows and repeat side effects. Size it to the provider's retry horizon — minutes — keep it below the deletion so a half-finished first delivery cannot suppress the work, and accept that losing the store only readmits duplicates.
  • Two notices for the same researcher arrive seconds apart: one names a provider sign-in, the other only the subject. What happens?
    The first resolves to one local session and deletes it; the second resolves to the whole set, finds the remainder and deletes that. Both succeed, the order does not matter, and the end state is identical either way — which is precisely the property convergence was chosen for.
  • A notice delivered through a hidden browser frame is never executed. How do you find out?
    From your server, you do not: the request simply never arrives, and a missing request looks exactly like a researcher who never signed out. It is an accepted residual to state in the design rather than something to detect. The only lever you hold is how long an unreached local session may survive.

saying these in an interview costs you the question

  • Returns an error when the named session is already gone
  • Assumes each notice is delivered exactly once
  • Relies on a replay cache for correctness instead of convergence
  • Claims the sign-out also revokes standing third-party grants
  • Counts an unexecuted browser frame as proof a session ended
  • Treats a duplicate delivery as an incident worth paging on