Skip to content

fix(bff): keep a logout tombstone in MemoryStore - #121

Merged
ovander merged 1 commit into
mainfrom
fix/memory-store-tombstones
Oct 11, 2026
Merged

ovander merged 1 commit into
mainfrom
fix/memory-store-tombstones

Conversation

@ovander

@ovander ovander commented Oct 11, 2026

Copy link
Copy Markdown
Owner

What and why

MemoryStore.Delete removed a session, but Put re-inserted it unconditionally. So a request that read the session just before a logout could bring it back by writing it later, with tokens the logout had just revoked. Two writes do that:

  • the Gateway's touch in the proxy;
  • a token refresh writing the rotated tokens back (gateway.go, Store.Put).

PostgresStore has always prevented this with a one-hour tombstone. This was found while moving the monitoring console to backendkit's stores (ovander/oauth2-monitoring#64), where it had to work around the gap for its own handlers.

  • Delete now records a tombstone for PostgresStoreTombstoneTTL (an hour).
  • Put ignores a tombstoned session, as PostgresStore's Put does.
  • An expired session evicted by Get goes through Delete, so a stale write-back can't revive it either.
  • Sweep also drops tombstones older than the TTL, so the map stays bounded by an hour of logouts.
  • Docs: the MemoryStore and Put/Delete/Sweep doc comments, the TTL constant's comment and the README.

How it was tested

  • TestMemoryStoreDeleteKeepsTombstone: a Put after Delete is ignored, and unrelated sessions are unaffected. The tombstone survives a sweep within the TTL and is dropped after it.

  • TestMemoryStoreExpiredGetIsTombstoned: a touched write-back of an idle-expired session doesn't revive it.

  • TestMemoryStoreConcurrentLogout: 8 goroutines Put and Get while Delete runs; after Delete, no Put brings the session back. Run with -race -count=3.

  • With the tombstone check removed from Put, all three fail.

  • go mod tidy && git diff --exit-code go.sum leaves go.sum unchanged

  • go build ./... passes

  • go vet ./... passes

  • go test -race -count=1 -timeout=120s ./... passes, also bff on the go 1.26.0 floor

  • golangci-lint run ./... (v2.14.0) reports no issue

  • govulncheck ./...: not run locally (vuln.go.dev is blocked here); CI runs it. No dependency change.

  • A line is added under ## [Unreleased] in CHANGELOG.md (### Fixed)

Compatibility

  • Exported-API change: no new or changed symbol. The doc of PostgresStoreTombstoneTTL notes MemoryStore uses it too.
  • Behaviour change for existing callers: a Put of a session deleted less than an hour ago is dropped.
    • Session IDs are random per sign-in (RandomToken), so only a write-back of the deleted session is affected, which is the bug.
    • A caller that deliberately re-created a session under the same ID after deleting it would see the write ignored. Nothing in the suite does that.
  • Breaking change: none.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GKRxaeYxyDhmt42cehLsGA


Generated by Claude Code

A request that read a session just before a logout (the Gateway's touch
in the proxy, or a token refresh writing rotated tokens back) called Put
after Delete and re-inserted the session, with tokens the logout had
just revoked. Delete now keeps a tombstone for PostgresStoreTombstoneTTL,
as PostgresStore always has; Put ignores a tombstoned session and Sweep
drops tombstones older than the TTL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKRxaeYxyDhmt42cehLsGA
@ovander
ovander merged commit e4bb958 into main Oct 11, 2026
4 checks passed
ovander pushed a commit that referenced this pull request Oct 11, 2026
Moves [Unreleased] under [1.26.1] - 2026-10-11 (#121 MemoryStore logout tombstones), updates the compare links and the README install snippet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKRxaeYxyDhmt42cehLsGA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants