better-auth-steam
v0.2.3
Published
Steam OpenID 2.0 plugin for Better Auth
Maintainers
Readme
better-auth-steam
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
Install
pnpm add better-auth-steamServer usage
import { 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!
})
]
});Options
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
Client plugin
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.
Link an account
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'
});Schema behavior
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.
Security notes
- 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.
Development
pnpm install
pnpm run lint
pnpm run test
pnpm run typecheck
pnpm run build