Steam

Steam OpenID 2.0

Code Exchange para web e mobile — Steam usa OpenID 2.0 (não OAuth2), nunca devolve e-mail, Web API key opcional para enriquecer o perfil, referência da API e exemplos de frontend.

Visão geral

O login Steam é opcional e controlado por STEAM_AUTH_ENABLED. Quando desligado, os endpoints Steam respondem 503 Service Unavailable. Diferente dos provedores OAuth2, o Steam usa OpenID 2.0 em https://steamcommunity.com/openid/login — não há client secret e o Steam nunca devolve endereço de e-mail. A API atribui um e-mail sintético estável {steamId}@users.noreply.steamcommunity.com para o upsert da conta. JWTs nunca vão na URL de redirect; a API emite um exchangeCode de uso único (Redis, 60 segundos). O mesmo POST /auth/exchange é compartilhado com os demais provedores sociais.

  • • Feature flag via environment
  • • Strategy passport OpenID 2.0 customizada + SteamAuthGuard (não OAuth2)
  • • Identidade verificada via POST check_authentication em steamcommunity.com/openid/login
  • • SteamID64 extraído de openid.claimed_id — armazenado como steamId
  • • Sem e-mail do Steam — sintético {steamId}@users.noreply.steamcommunity.com
  • • Nome de persona opcional via GET https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/ quando STEAM_API_KEY está definida
  • • Allowlist de redirect evita open redirects
  • • Mesmo formato de resposta de token que POST /auth/login

Configuração Steam

O login OpenID do Steam não exige conta Steamworks partner. Opcionalmente registre uma Web API key em steamcommunity.com/dev/apikey para enriquecer perfis com GetPlayerSummaries (persona name). Defina STEAM_CALLBACK_URL e STEAM_REALM no environment — a API redireciona usuários para https://steamcommunity.com/openid/login.

  1. Abra https://steamcommunity.com/dev/apikey (opcional — para enriquecimento via GetPlayerSummaries)
  2. Registre um domínio e copie a Web API key para STEAM_API_KEY (OpenID funciona sem ela)
  3. Defina STEAM_CALLBACK_URL para o callback da API Nest (ex.: http://localhost:3000/api/v1/auth/steam/callback)
  4. Defina STEAM_REALM para a origem da API (ex.: http://localhost:3000/) — enviado como openid.realm
  5. Garanta que STEAM_REDIRECT_ALLOWLIST inclua URLs da SPA ou deep links mobile
  6. Ative STEAM_AUTH_ENABLED=true no .env

Variáveis de ambiente

Carregadas do .env via src/config/steam-openid.config.ts (namespace steamOpenId no ConfigService). Veja .env.example. STEAM_API_KEY é opcional — a identidade OpenID funciona sem ela.

Environment.env
STEAM_AUTH_ENABLED=true
STEAM_API_KEY=your-steam-web-api-key
STEAM_CALLBACK_URL=http://localhost:3000/api/v1/auth/steam/callback
STEAM_REALM=http://localhost:3000/
STEAM_REDIRECT_ALLOWLIST=myapp://success,http://localhost:5173/auth/callback
STEAM_OAUTH_DEFAULT_ROLES=

Roles padrão para novos usuários Steam

Novos usuários Steam recebem roles: [] por padrão (igual ao register). Defina STEAM_OAUTH_DEFAULT_ROLES no .env como lista separada por vírgula (ex.: user ou user,manager). Usuários existentes vinculados por steamId mantêm as roles atuais.

Sequência

  1. Cliente abre GET /api/v1/auth/steam?redirect=<URL na allowlist>
  2. API redireciona para Steam OpenID (checkid_setup); usuário faz login no Steam
  3. Browser chama GET /api/v1/auth/steam/callback com query openid.*; API verifica via check_authentication
  4. API opcionalmente chama GetPlayerSummaries, faz upsert por steamId, grava exchangeCode no Redis e redireciona para redirect?code=...
  5. Cliente faz POST { code } em /api/v1/auth/exchange e recebe JWTs

Referência da API

1. Iniciar login OpenID

Redireciona o browser para https://steamcommunity.com/openid/login com OpenID 2.0 checkid_setup (não é URL OAuth2 authorize). O query redirect deve bater com um prefixo de STEAM_REDIRECT_ALLOWLIST (ou omita para usar a primeira entrada). Usa STEAM_REALM e STEAM_CALLBACK_URL.

HTTPGET /api/v1/auth/steam
GET /api/v1/auth/steam?redirect=http%3A%2F%2Flocalhost%3A5173%2Fauth%2Fcallback

400 redirect inválido · 503 feature desligada

2. Callback

Tratado pela API. O Steam devolve openid.mode=id_res e demais parâmetros openid.*. A API faz POST check_authentication para verificar, extrai SteamID64 de openid.claimed_id e redireciona para o app com ?code= (exchange code, não authorization code OAuth).

HTTPGET /api/v1/auth/steam/callback
GET /api/v1/auth/steam/callback?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.claimed_id=https%3A%2F%2Fsteamcommunity.com%2Fopenid%2Fid%2F76561198012345678&state=...
→ 302 Location: http://localhost:5173/auth/callback?code=EXCHANGE_CODE

3. Trocar código

Endpoint público compartilhado com outros provedores sociais. Consome o código (uso único) e devolve o mesmo formato do login.

HTTP RequestPOST /api/v1/auth/exchange
POST /api/v1/auth/exchange
Content-Type: application/json

{
  "code": "EXCHANGE_CODE"
}
HTTP Response200 OK
{
  "user": {
    "id": "...",
    "email": "[email protected]",
    "firstName": "PlayerName",
    "lastName": "",
    "roles": [],
    "steamId": "76561198012345678",
    "isActive": true
  },
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

401 código inválido/expirado/usado · 503 auth social desligada

Frontend — Web (SPA)

Mesmo padrão dos provedores OAuth: iniciar login no browser; sua rota de callback lê code da query e chama exchange. O objeto user inclui steamId e e-mail sintético — não use para envio de e-mail.

JavaScriptIniciar login Steam
const API = 'http://localhost:3000/api/v1';
const redirect = encodeURIComponent(
  'http://localhost:5173/auth/callback'
);

// Redirect de página inteira: Nest → Steam OpenID → de volta à SPA
window.location.href = `${API}/auth/steam?redirect=${redirect}`;
JavaScriptPágina de callback /auth/callback
// /auth/callback na SPA
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
if (!code) throw new Error('Missing exchange code');

const res = await fetch('http://localhost:3000/api/v1/auth/exchange', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ code }),
});
if (!res.ok) throw new Error(await res.text());

const { user, accessToken, refreshToken } = await res.json();
// persista os tokens como sua app exigir
sessionStorage.setItem('accessToken', accessToken);
// Steam não tem e-mail real — use steamId como identificador estável
console.log('signed in', user.steamId);
  • • Inclua a URL de callback do frontend em STEAM_REDIRECT_ALLOWLIST (ex.: http://localhost:5173/auth/callback)
  • • STEAM_CALLBACK_URL aponta para a API Nest, não para a SPA
  • • Steam nunca devolve e-mail real — user.email é sintético e não entregável
  • • Armazene accessToken / refreshToken com segurança (memória + httpOnly cookie conforme sua app)

Frontend — Mobile (deep link)

Use um scheme customizado (ou universal link) na allowlist. Após Steam OpenID, a API redireciona para myapp://success?code=.... O app abre, lê o código e chama exchange.

React NativeAbrir OpenID no browser
import * as Linking from 'expo-linking';
import * as WebBrowser from 'expo-web-browser';

const API = 'https://api.example.com/api/v1';
const redirect = encodeURIComponent('myapp://success');

async function signInWithSteam() {
  const url = `${API}/auth/steam?redirect=${redirect}`;
  await WebBrowser.openAuthSessionAsync(url, 'myapp://success');
}
React NativeTratar deep link + exchange
import * as Linking from 'expo-linking';

async function exchangeFromUrl(url) {
  const { queryParams } = Linking.parse(url);
  const code = queryParams?.code;
  if (!code) return;

  const res = await fetch(`${API}/auth/exchange`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code }),
  });
  const data = await res.json();
  // data.accessToken, data.refreshToken, data.user
  return data;
}

Linking.addEventListener('url', ({ url }) => {
  exchangeFromUrl(url);
});
  • • Registre o scheme no SO / Expo app.json
  • • Prefira Linking.addEventListener('url', ...) e getInitialURL()
  • • Exchange via HTTPS na URL base da API
  • • Identifique usuários por steamId — não pelo e-mail sintético

Notas de segurança

  • • Steam usa OpenID 2.0, não OAuth2 — sem client secret; verifique respostas com check_authentication
  • • URLs de redirect devem casar com prefixos de STEAM_REDIRECT_ALLOWLIST
  • • Exchange codes são de uso único e expiram em 60 segundos (Redis)
  • • Steam nunca fornece e-mail — endereço sintético é só para upsert interno, não para notificações
  • • Contas existentes são vinculadas por steamId; linking por e-mail não se aplica a usuários só-Steam
  • • Usuários só-Steam têm password null — login/change-password com senha falham até haver senha

Modelo de usuário

Campos da entity/interface usados pelo login Steam:

  • • steamId — SteamID64 único e nullable (de openid.claimed_id)
  • • email — sintético {steamId}@users.noreply.steamcommunity.com (Steam não expõe e-mail)
  • • password — nullable para contas só OpenID
  • • isActive — true para novos usuários Steam
  • • roles — de STEAM_OAUTH_DEFAULT_ROLES no env (padrão [])

Relacionados