Skip to content

Steam desktop authentication support (SteamSDK, Auth branch, audience config, username seeding) - #4683

Merged
Celant merged 10 commits into
mainfrom
steam-desktop-auth
Jul 23, 2026
Merged

Steam desktop authentication support (SteamSDK, Auth branch, audience config, username seeding)#4683
Celant merged 10 commits into
mainfrom
steam-desktop-auth

Conversation

@Celant

@Celant Celant commented Jul 23, 2026

Copy link
Copy Markdown
Member

Maintainer note: part of the private OpenFront Steam release (Milestone 2, tracked in Linear), not a public GitHub issue. Per the contributor policy this needs an approved/assigned issue or a maintainer label to avoid auto-close — flagging for a maintainer to handle.

Resolves: n/a — private Steam-release work (see note above)

Description:

Adds the client-side pieces for authenticating the OpenFront Steam desktop build (an Electron shell) against the existing API, mirroring the established CrazyGames integration. The native Steamworks code lives in the desktop shell and is exposed to this client through a window.openfrontDesktop.steam bridge; this PR is the renderer half.

  • SteamSDK.ts (new) — thin wrapper over the desktop shell's Steam bridge (isOnSteam / getTicket / getUser), mirroring CrazyGamesSDK; narrows the loosely-typed window.openfrontDesktop locally rather than re-declaring it.
  • Auth.ts — a Steam branch at the top of doRefreshJwt() plus doSteamLogin(), exchanging a Steam Web-API ticket at POST /auth/steam for a session JWT, exactly paralleling doCrazyGamesLogin. Re-exchanges on expiry (the refresh cookie is cross-site-blocked from the app:// origin); no ticket / not on Steam falls through to the existing flow.
  • Api.tsgetAudience() now sources from BOOTSTRAP_CONFIG (ClientEnv.jwtAudience()) instead of window.location, so the desktop app (running at app://openfront) resolves the real API base. Behavior-preserving on web, where the injected audience already equals the hostname-derived one.
  • UsernameInput.ts — seeds the in-game display name from the Steam persona on first launch and persists it (unlike CrazyGames). Writes only the local display name; never the account username.
  • SteamLinkSignpost.ts (new) — a one-time, dismissible notice shown on first Steam launch that account linking is coming.

Please complete the following:

  • I have added screenshots for all UI updates — ⚠️ the new first-launch link signpost is a UI addition; it renders only inside the Steam desktop shell. Screenshots to be added by the maintainer.
  • I process any text displayed to the user through translateText() and I've added it to the en.json file — signpost strings go through translateText() with keys added to resources/lang/en.json (steam.link_signpost, common.got_it).
  • I have added relevant tests to the test directory — unit tests for SteamSDK (incl. bridge-throws degradation), the Auth.ts Steam exchange + fall-through, the Api.ts audience change, username seeding, and the signpost gating. Full suite green (1976) + tsc --noEmit clean.

Please put your Discord username so you can be contacted if a bug or regression is found:

⚠️ maintainer to fill

🤖 Generated with Claude Code

https://claude.ai/code/session_01BWxUzYb2uqjcBFQuNSJhMy

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 45c43c7b-1236-4828-84fc-427454e94348

📥 Commits

Reviewing files that changed from the base of the PR and between b541c95 and caf68d3.

📒 Files selected for processing (1)
  • tests/Api.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/Api.test.ts

Walkthrough

Adds Steam bridge access, Steam ticket login, Steam-based username seeding, and a dismissible account-linking signpost. API audience selection now uses injected configuration, with localization and tests covering the new behavior.

Changes

Steam integration

Layer / File(s) Summary
Steam runtime bridge and environment wiring
src/client/SteamSDK.ts, src/client/Api.ts, tests/Api.test.ts, tests/SteamSDK.test.ts, tests/client/components/FeaturedStream.test.ts
Adds safe Steam bridge access, nullable ticket/user getters, singleton SDK access, injected API audience selection, and environment-isolated tests.
Steam ticket authentication
src/client/Auth.ts, tests/client/Auth.steam.test.ts
Attempts /auth/steam login during JWT refresh when a Steam ticket is available, stores returned session data, and preserves fallback authentication when it is not.
Steam account UI and identity seeding
src/client/SteamLinkSignpost.ts, src/client/UsernameInput.ts, src/client/Main.ts, src/client/SinglePlayerModal.ts, index.html, resources/lang/en.json, tests/client/SteamLinkSignpost.test.ts, tests/client/UsernameInput.steam.test.ts
Adds Steam username initialization, waits for seeding before lobby creation, and mounts a localized one-time signpost dismissed through local storage.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant SteamSDK
  participant AuthEndpoint
  Client->>SteamSDK: Request Steam ticket
  SteamSDK-->>Client: Return ticket
  Client->>AuthEndpoint: POST ticket to /auth/steam
  AuthEndpoint-->>Client: Return JWT and expiry
  Client->>Client: Store session and render Steam UI
Loading

Possibly related PRs

Suggested labels: Feature, UI/UX, Translation

Poem

Steam tickets cross the night,
Names appear in desktop light.
A signpost says, “Got it,” then
Sleeps until it’s needed again.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: Steam desktop authentication and related client-side support.
Description check ✅ Passed The description is directly related to the changeset and explains the Steam auth, API audience, username seeding, and signpost work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/UsernameInput.ts`:
- Around line 123-134: Update UsernameInput’s Steam seeding flow so
getUsername() is not consumed by handleJoinLobby() until the asynchronous
steamSDK.getUser() lookup has completed. Expose and await a readiness promise in
the join path, preserve the generated anonymous username when lookup fails or
returns no name, and prevent a late Steam result from overwriting a username
entered by the player.
- Around line 123-134: Update the Steam persona seeding in UsernameInput’s
noStoredUsername block to normalize user.name with the same bracket-removal
logic used by handleUsernameChange, then validate the normalized value before
assigning baseUsername or calling validateAndStore. Only replace the generated
fallback when the persona is valid; otherwise leave it unchanged and avoid
setting validationError.

In `@tests/Api.test.ts`:
- Around line 5-18: Update the test lifecycle around setConfig and the
getAudience/getApiBase suite to delete window.BOOTSTRAP_CONFIG before calling
ClientEnv.reset() in both beforeEach and afterEach, ensuring each test starts
and ends without inherited configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d77dbbfb-255d-44bf-b037-d749bef7a2d4

📥 Commits

Reviewing files that changed from the base of the PR and between d76a0c4 and 7ff8c7f.

📒 Files selected for processing (14)
  • index.html
  • resources/lang/en.json
  • src/client/Api.ts
  • src/client/Auth.ts
  • src/client/DesktopShell.ts
  • src/client/Main.ts
  • src/client/SteamLinkSignpost.ts
  • src/client/SteamSDK.ts
  • src/client/UsernameInput.ts
  • tests/Api.test.ts
  • tests/SteamSDK.test.ts
  • tests/client/Auth.steam.test.ts
  • tests/client/SteamLinkSignpost.test.ts
  • tests/client/UsernameInput.steam.test.ts

Comment thread src/client/UsernameInput.ts
Comment thread tests/Api.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/client/UsernameInput.steam.test.ts`:
- Around line 49-61: Update the test "keeps a valid generated name when the
persona is invalid" to capture the UsernameInput-generated username before the
asynchronous Steam lookup resolves, then assert the post-resolution username
equals that captured value. Keep the existing checks that the fallback is
non-empty and differs from the invalid Steam name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b197cab9-b801-4e4e-a431-64ba39a50379

📥 Commits

Reviewing files that changed from the base of the PR and between e361a2c and b9ac9ff.

📒 Files selected for processing (5)
  • src/client/SteamSDK.ts
  • src/client/UsernameInput.ts
  • tests/SteamSDK.test.ts
  • tests/client/Auth.steam.test.ts
  • tests/client/UsernameInput.steam.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/client/SteamSDK.ts
  • tests/client/Auth.steam.test.ts
  • tests/SteamSDK.test.ts
  • src/client/UsernameInput.ts

Comment thread tests/client/UsernameInput.steam.test.ts
Celant added 9 commits July 23, 2026 13:11
getAudience() previously derived the audience from window.location, which
resolves to the unreachable 'api.openfront' on the Electron desktop app
(app://openfront). Source it from ClientEnv.jwtAudience() (BOOTSTRAP_CONFIG)
instead so the desktop app targets real infra. Behavior-preserving on web,
where jwtAudience already equals the hostname-derived audience.

getApiBase() is unchanged (still derives from getAudience()); the
'localhost' branch keeps working since jwtAudience() is 'localhost' in
local dev.
Adds SteamLinkSignpost, a self-hiding Lit component shown once on first
Steam launch to tell existing web players that account linking isn't
available yet (a fresh Steam launch creates a new account). Tracked via
a localStorage seen-flag, dismissible, and a no-op off Steam so it's
safe to mount unconditionally on web too.

Registered in Main.ts and mounted in index.html alongside the other
top-level toast (marketing-consent-toast). Adds the steam.link_signpost
i18n key and a missing common.got_it key (used by the dismiss button;
the existing "got_it" string was namespaced under ios_banner, not
common).
Addresses review: normalize the Steam persona (strip brackets, trim) and
only accept it when it passes validateUsername, else keep the generated
name; don't let a late getUser() result overwrite a name the player typed.
Prettier-format the Steam files (were ESLint-clean but never formatted).
@Celant
Celant merged commit 2ecdbdf into main Jul 23, 2026
13 checks passed
@Celant
Celant deleted the steam-desktop-auth branch July 23, 2026 13:13
@github-project-automation github-project-automation Bot moved this from Development to Complete in OpenFront Release Management Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

1 participant