Steam OpenID 2.0 plugin for Better Auth 1.6.21 or later.
It adds a Steam sign-in and account-link flow:
POST /api/auth/steam/loginPOST /api/auth/steam/linkGET /api/auth/steam/callback
pnpm add better-auth-steamimport { betterAuth } from 'better-auth/minimal';
import { steamOpenID } from 'better-auth-steam';
export const auth = betterAuth({
trustedOrigins: ['https://app.example.com'],
account: {
accountLinking: {
allowDifferentEmails: true
}
},
plugins: [
steamOpenID({
apiKey: process.env.STEAM_API_KEY!
})
]
});type SteamPluginOptions = {
apiKey: string;
syntheticEmailDomain?: string;
overrideUserInfoOnSignIn?: boolean;
mapProfileToUser?: (profile: SteamPlayerSummary) => {
name?: string;
email?: string;
image?: string | null;
};
schema?: {
user?: {
modelName?: string;
fields?: { steamId?: string };
};
};
};apiKey: Steam Web API key from https://steamcommunity.com/dev/apikeysyntheticEmailDomain: used to generate fallback emails, defaults tosteam.invalidoverrideUserInfoOnSignIn: update mapped profile fields for existing users, defaults tofalsemapProfileToUser: optional mapping function for Steam profile fieldsschema: rename thesteamIdfield or theusermodel
import { createAuthClient } from 'better-auth/client';
import { steamOpenIDClient } from 'better-auth-steam/client';
export const authClient = createAuthClient({
plugins: [steamOpenIDClient()]
});
await authClient.steam.login({
callbackURL: '/account',
errorCallbackURL: '/sign-in'
});The client follows the URL in the Better Auth redirect response.
The sign-in endpoint changed from GET to POST. Replace direct links to the
old endpoint with the client call or a POST request. The plugin also returns
stable STEAM_* error codes instead of raw internal error text.
Account linking requires an authenticated session. Steam does not provide an email address, so Better Auth must permit links between different email addresses.
await authClient.steam.link({
callbackURL: '/settings/accounts',
errorCallbackURL: '/settings/accounts'
});The plugin adds a nullable unique steamId field on the Better Auth user model.
account.providerId:steamaccount.accountId: SteamID64user.steamId: SteamID64
The plugin creates a synthetic email because Better Auth requires an email on the user record. The plugin marks this email as unverified. Steam does not provide or verify email addresses.
- Better Auth state binds each callback to the browser that started the flow.
- Callback URLs must match Better Auth
trustedOriginsor use a relative path. - The callback validates required OpenID fields, signed fields, the exact
return_toURL, and the Steam identity before it creates a session. - The plugin validates the assertion with Steam through
check_authentication. - The plugin reserves each accepted Steam response nonce to prevent replay across separate sign-in states.
- Steam requests use a 10-second timeout and do not follow redirects.
- Steam never uses implicit email-based account linking. Use the authenticated link endpoint to connect Steam to an existing user.
pnpm install
pnpm run lint
pnpm run test
pnpm run typecheck
pnpm run build