Skip to content

fix: link Steam, Xbox and Battle.net after catapult-api restarts - #124

Open
enimaloc wants to merge 2 commits into
devfrom
fix/oauth-link-session
Open

enimaloc wants to merge 2 commits into
devfrom
fix/oauth-link-session

Conversation

@enimaloc

@enimaloc enimaloc commented Nov 14, 2026 •

Copy link
Copy Markdown
Owner

Problem

In prod, linking Battle.net right after the 1.3.1 deploy failed with BATTLENET link attempted without an authenticated Twitch session. A secondary link's callback (Steam, Xbox, Battle.net) reads the user from catapult-api's own HTTP session (CATAPULT_API_SESSION), which lives in memory: every catapult-api restart loses it, while catapult-web still shows the user logged in. Until the user logs in with Twitch again, every link fails.

Fix

  • catapult-web (ApiRelayController): when relaying /oauth2/authorization/<provider> (except twitch), it sends the session's JWT as Authorization: Bearer, replacing any header the visitor sent.
  • catapult-api (LinkSessionRestoreFilter, before Spring Security): on those paths, a valid token is checked with the same JwtDecoder as /api/** (signature, expiry, fictitious accounts). If it names an active account, that account is put in the session, so the callback finds it as before.
    • A session that already holds the same user is left untouched.
    • A stale session of another user is replaced, so the link no longer goes to the previous account on a shared browser.
    • The session id changes whenever the user is set (session fixation).
    • An invalid token, an unknown or inactive account, or no token restores nothing, and behaviour stays as before.
    • While an admin impersonates a member, nothing is restored: catapult-web sends no JWT, and catapult-api refuses tokens carrying ROLE_PREVIOUS_ADMINISTRATOR. An admin's own provider account is never linked to the member's.
  • The filter resolves JwtDecoder and UserAccountRepository on use: as a servlet filter it is picked up by every @WebMvcTest slice, which has neither bean.

Checks

  • Unit tests: LinkSessionRestoreFilterTest (6), plus 3 new cases in ApiRelayControllerTest. The full catapult-api and catapult-web suites pass locally.
  • A local bootRun of catapult-api starts with the new filter.

Modules to restart: catapult-api and catapult-web, deployed together. Either one alone changes nothing; neither breaks the other.

A link's callback reads the user from catapult-api's in-memory session,
lost on every restart while catapult-web still shows the user logged in.
catapult-web now relays the user's JWT when a link starts, and catapult-api
restores its session from it, replacing a stale session of another user.
An admin acting as a member must not link their own Steam, Xbox or
Battle.net account to the member's: catapult-web sends no JWT then, and
catapult-api refuses impersonation tokens. The filter also resolves its
beans on use, so web test slices that pick it up still load.
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.

1 participant