-
Notifications
You must be signed in to change notification settings - Fork 0
Steam Auth Flow
This page documents the current Steam sign-in flow used by the proton-pulse-web GitHub Pages site, along with the regression we hit after adding the login interstitial on April 16, 2026.
This is for the static site in proton-pulse-web, not the Decky plugin runtime.
Relevant files:
proton-pulse-web/js/lib/supabase-client.jsproton-pulse-web/auth.htmlproton-pulse-web/js/auth/main.jsproton-pulse-web/js/profile/main.jsproton-pulse-web/supabase/functions/steam-callback/index.ts
- A logged-out user clicks
Login with Steamfromindex.html,app.html, orprofile.html. - The site sends them to
auth.html?returnTo=<current-page-url>. -
auth.jsreadsreturnToand callsSupaAuth.loginWithSteam(returnTo)when the user continues. -
supabase-client.jsredirects to Steam OpenID with:openid.return_to=<supabase edge function url>?returnTo=<original-page-url>openid.realm=<supabase edge function url>
- Steam redirects to the Supabase Edge Function at
functions/v1/steam-callback. - The callback verifies the OpenID assertion with Steam, signs the user into Supabase, then redirects back to the site.
- The site receives
#access_token=...&refresh_token=...&type=steamin the URL hash. -
supabase-client.jsconsumes that hash via_sb.auth.setSession(...), removes the hash from the URL, and only then letsgetSession()and initial auth-state consumers proceed.
Users saw:
{"code":"UNAUTHORIZED_NO_AUTH_HEADER","message":"Missing authorization header"}
and login sometimes appeared to land on the wrong page after the Steam round-trip.
Commit 14e421b6f on April 16, 2026 added a Steam login interstitial and introduced buildLoginPageUrl(returnTo).
That change was fine on the entry side, but it left two gaps:
-
returnTowas never preserved through the Edge Function callback. - Session restoration from the callback hash was kicked off asynchronously, but nothing waited for it before early auth-dependent code called
getSession()or subscribed to initial auth state.
There were two separate issues:
The interstitial correctly stored returnTo, but steam-callback/index.ts always redirected to SITE_URL root instead of the originating page.
consumeSessionFromHash() called setSession(...), but the rest of the client boot continued immediately.
That meant a protected request could happen before the Steam access token had actually been restored into the Supabase client session, producing a missing auth header on requests that expected a real bearer token.
The fix has three parts:
supabase-client.js now:
- normalizes
returnToto same-origin URLs only - adds that
returnToto the Edge Function callback URL - exposes the same normalized value through
buildLoginPageUrl(...)
supabase-client.js now stores the startup promise:
const _sessionReady = consumeSessionFromHash();
and then waits for it in:
getSession()- initial
onStateChange(...)registration flow
That removes the startup race after the Steam callback returns with the auth hash.
supabase/functions/steam-callback/index.ts now:
- reads
returnTofrom its own query string - validates that the parsed URL stays on the site origin
- redirects there instead of always redirecting to
SITE_URL
This auth flow has two deployment surfaces:
These changes are needed for:
supabase-client.jsauth.htmlauth.js- page shell files that launch the login flow
Publishing Pages updates alone is not enough to activate callback changes.
Changes in supabase/functions/steam-callback/index.ts only take effect after the function is redeployed to Supabase.
If the Pages files are updated but the Edge Function is not, the client can improve session timing, but callback redirect behavior will still reflect the old deployed function.
When changing Steam auth again:
- Verify
buildLoginPageUrl(...),loginWithSteam(...), andsteam-callback/index.tsall agree on howreturnTois passed. - Keep callback redirects same-origin only.
- Ensure startup auth consumers wait until callback-hash session restoration completes.
- Deploy both:
- GitHub Pages shell files
- Supabase
steam-callbackEdge Function
- Test from at least two entry points:
- home page top-bar login
-
profile.htmlsigned-out login
- Confirm post-login return lands back on the page where sign-in started.
After a successful Steam sign-in:
- the user should return to the page they started from
- the URL hash should be cleared after session restoration
-
SupaAuth.getSession()should return a valid session - authenticated requests should send a real bearer token, not fall back to an unauthenticated request path