feat(providers): add Steam OpenID 2.0 provider#13432
Open
codewithkashi wants to merge 1 commit into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
@codewithkashi is attempting to deploy a commit to the authjs Team on Vercel. A member of the Team first needs to authorize it. |
Author
|
@ThangHuuVu Kindly have a look |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Goals
Add a built-in Steam provider to @auth/core so developers can authenticate Steam users without third-party packages
Implement Steam's OpenID 2.0 verification using only the Web-standard fetch API — no Node.js-only dependencies — so it works on Edge, Cloudflare Workers, Deno, and Bun
Add a small token.request hook to handleOAuth in the core callback handler, enabling Auth.js to support authentication protocols that differ from the OAuth 2.0 authorization-code grant (OpenID 2.0, custom flows, etc.)
Non-Goals
Supporting Steam's full Web API beyond authentication (inventory, achievements, game data, etc.) — that is the app's responsibility after sign-in
Migrating or deprecating the existing community package next-auth-steam — this proposal is additive
Supporting other OpenID 2.0 providers in this PR — the token.request hook makes that possible in future, but only Steam is implemented here
Background
Steam is one of the most requested auth providers in the Auth.js ecosystem. It has over 35 million daily active users and is the dominant identity system in PC gaming. Developers building gaming dashboards, tournament platforms, and community sites routinely need Steam login.
Why Steam is not already supported:
Steam uses OpenID 2.0 — a protocol older than and fundamentally incompatible with OAuth 2.0. Every built-in Auth.js provider (Google, GitHub, Discord, etc.) uses OAuth 2.0 or OIDC. OpenID 2.0 has no authorization code — Steam redirects the user back to your callback URL with a signed assertion in the query string, which must then be verified by re-posting those params to Steam's endpoint with openid.mode=check_authentication.
Current alternatives:
next-auth-steam (https://github.com/Nekonyx/next-auth-steam) — a community package with ~100 stars. It works but has two problems:
It depends on the openid npm package which is Node.js-only (uses callback-style RelyingParty), breaking Edge and serverless runtimes
It accepts NextApiRequest directly, making it framework-specific and incompatible with the framework-agnostic Auth.js v5 core
The core blocker:
Auth.js v5's handleOAuth callback handler has no hook to bypass the oauth4webapi authorization-code grant flow. Without a token.request escape hatch, it is impossible to implement a non-OAuth-2.0 provider cleanly from the outside.
I have a working implementation that solves all of these issues, which I am proposing to contribute.
Proposal
I have a complete working implementation ready to submit as a PR. It consists of two changes:
A fully typed Steam provider following the exact same structure as all other built-in providers. Key implementation details:
authorization: Sends the user to https://steamcommunity.com/openid/login with the correct OpenID 2.0 params (openid.mode=checkid_setup, openid.ns, openid.realm, openid.return_to)
checks: ["none"] — OpenID 2.0 uses its own replay-protection (openid.nonce + openid.sig), not PKCE or OAuth state
token.request: Receives the raw OpenID assertion params from Steam's callback URL, re-posts them to Steam with openid.mode=check_authentication using the Web-standard fetch API (no openid npm package, no Node.js-only code), extracts the Steam ID, and returns it as access_token
userinfo.request: Uses the Steam ID from access_token to call the Steam Web API GetPlayerSummaries endpoint with the user's API key (clientSecret)
profile(): Maps the Steam profile to Auth.js's standard { id, name, email, image } shape. Since Steam does not expose email addresses publicly, a synthesized email (steamid@steamcommunity.com) is used — documented clearly in a JSDoc note
2. packages/core/src/lib/actions/callback/oauth/callback.ts (small modification)
A single new if-branch added before the oauth4webapi code-grant call:
if (provider.token?.request) {
// call token.request with the OpenID callback params
// then call userinfo.request with the resulting tokens
// return early — skip the entire oauth4webapi flow
}
// existing code continues unchanged for all OAuth 2.0 providers
This is fully backward-compatible. Every existing provider that does not set token.request falls through to the existing code path unchanged.
Tests:
13 unit tests covering config shape, authorization URL construction, profile mapping, token.request (valid assertion, is_valid:false, wrong endpoint, bad claimed_id), and userinfo.request (success, missing token, empty player list). All tests pass.