Skip to content

feat(providers): add Steam OpenID 2.0 provider#13432

Open
codewithkashi wants to merge 1 commit into
nextauthjs:mainfrom
codewithkashi:feat/steam-provider
Open

feat(providers): add Steam OpenID 2.0 provider#13432
codewithkashi wants to merge 1 commit into
nextauthjs:mainfrom
codewithkashi:feat/steam-provider

Conversation

@codewithkashi
Copy link
Copy Markdown

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:

  1. packages/core/src/providers/steam.ts (new file)

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.

@codewithkashi codewithkashi requested a review from ThangHuuVu as a code owner May 5, 2026 11:41
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
auth-docs Error Error May 5, 2026 11:41am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
next-auth-docs Ignored Ignored Preview May 5, 2026 11:41am

Request Review

@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

@codewithkashi is attempting to deploy a commit to the authjs Team on Vercel.

A member of the Team first needs to authorize it.

@codewithkashi
Copy link
Copy Markdown
Author

@ThangHuuVu Kindly have a look

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Refers to `@auth/core` providers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant