Pular para o conteúdo principal

Steam OAuth e Telegram OAuth com Casdoor: Adicionando Logins Sociais Não-Padrão Através de OIDC

· Leitura de 11 min
Yang Luo
Casdoor Maintainer

Não existe "Steam OAuth": o Steam autentica usuários com OpenID 2.0 e fornece um SteamID de 64 bits, nada além disso. O Login Widget clássico do Telegram também não é OAuth: ele entrega à sua página um conjunto de campos de usuário mais um hash HMAC-SHA256 que você verifica com o token do seu bot. O Telegram agora também executa um provedor real de OpenID Connect em oauth.telegram.org. Se você colocar o Casdoor entre sua aplicação e esses provedores, o Casdoor faz as verificações específicas do protocolo e sua aplicação só conversa com o Casdoor usando OpenID Connect, da mesma forma que faria com Google ou GitHub.

Os provedores em um relance​

ProvedorProtocoloO que identifica o usuárioEmail disponível?Tipo de provedor do Casdoor
SteamOpenID 2.0 em https://steamcommunity.com/openid/login, mais a API Web do Steam para o perfilSteamID64, obtido do ID reivindicado https://steamcommunity.com/openid/id/<steamid>NãoSteam
Telegram (Login Widget)Dados do widget assinados, HMAC-SHA256 com chave derivada do SHA-256 do token do botid do usuário do TelegramNãoTelegram
Telegram (OpenID Connect)Fluxo de código de autorização OIDC com PKCE em https://oauth.telegram.orgClaim sub do token de IDSem claim de email; telefone com o escopo phoneCustom
X (Twitter)Código de autorização OAuth 2.0 com PKCEID de usuário do X de /2/users/meNão com os escopos padrão do CasdoorTwitter
FacebookCódigo de autorização OAuth 2.0ID de usuário escopado pela aplicaçãoApenas se o perfil tiver um email primário válidoFacebook

O restante deste post passa pelo que cada protocolo realmente retorna e o que o Casdoor faz com isso.

Steam: OpenID 2.0, sem OAuth​

As páginas de desenvolvedores do Steam descrevem o Steam como um provedor OpenID: seu site envia o usuário para o Steam, e o Steam devolve um ID reivindicado no formato https://steamcommunity.com/openid/id/<steamid>. O número no final é o SteamID de 64 bits do usuário. Não há código de autorização, token de acesso, escopos nem email: nem a resposta do OpenID nem o perfil da API Web contêm um.

É por isso que buscas por "steam oauth" não levam a lugar útil: o protocolo é OpenID 2.0, predecessor do OpenID Connect, então uma biblioteca cliente de OAuth 2.0 ou OIDC não pode falar diretamente com o Steam.

O que o Casdoor faz para um login via Steam:

  1. A página de login do Casdoor constrói uma solicitação checkid_setup de OpenID 2.0 para https://steamcommunity.com/openid/login, com openid.realm definido como a origem do Casdoor e openid.return_to definido como a página /callback do Casdoor.
  2. Quando o Steam redireciona de volta, o Casdoor posta os campos assinados de volta para o Steam com openid.mode=check_authentication. Somente se o Steam responder is_valid:true ele continua. Ele também verifica se openid.claimed_id corresponde ao padrão steamcommunity.com/openid/id/<digits> e extrai o SteamID dele.
  3. Com a chave da API Web do Steam que você insere como Client secret do provedor, o Casdoor chama ISteamUser/GetPlayerSummaries para obter o nome de persona e o avatar.

O usuário resultante do Casdoor tem o SteamID64 como nome de usuário, o nome da persona do Steam como nome de exibição e o avatar do Steam. O campo de e-mail permanece vazio. O Casdoor remove intencionalmente o texto de placeholder que a biblioteca subjacente coloca lá. Se sua aplicação precisar de um endereço de e-mail, colete-o após o cadastro.

A configuração leva dois minutos: registre uma chave de API Web para o domínio do seu Casdoor na página de chaves da Steam, crie um provedor do tipo Steam e cole a chave como segredo do cliente. O guia do provedor Steam tem os passos.

Telegram: o Widget de Login e sua verificação HMAC​

O login clássico do Telegram é um widget JavaScript. Você cria um bot com @BotFather, vincula seu domínio a ele com /setdomain e incorpora o widget. Quando o usuário confirma no Telegram, o widget redireciona para a URL em data-auth-url ou chama uma função JavaScript, passando id, first_name, last_name, username, photo_url, auth_date e hash.

Nada nesse payload é um token. Qualquer pessoa pode digitar esses campos em uma URL, então o servidor deve verificar o hash. A verificação documentada pelo Telegram funciona assim:

data_check_string = all received fields except hash,
as key=value, sorted by key, joined with "\n"
secret_key = SHA256(bot_token)
valid = hex(HMAC_SHA256(data_check_string, secret_key)) == hash

O Telegram também recomenda verificar auth_date para que dados antigos não possam ser reproduzidos, mas deixa a janela de tempo por sua conta.

No Casdoor, o tipo de provedor Telegram usa o nome de usuário do bot (sem @) como Client ID e o token do bot como Client secret. Quando um usuário clica no botão do Telegram, o Casdoor abre sua própria página /telegram-login, que carrega telegram-widget.js de telegram.org com o nome de usuário do seu bot e aponta data-auth-url de volta para o /callback do Casdoor. O callback coleta os campos e o backend do Casdoor então:

  • reconstrói a string de verificação de dados a partir de todos os campos exceto hash, ordena-a e compara o HMAC-SHA256 contra hash usando SHA256(bot token) como chave;
  • rejeita os dados se auth_date tiver mais de 24 horas;
  • usa o id numérico do Telegram como identidade, o username como nome de usuário, o primeiro e último nome como nome de exibição, e photo_url como avatar.

Os nomes de usuário do Telegram são opcionais. Quando um usuário não possui um, o Casdoor gera telegram_<id>, que permanece o mesmo em cada login. O widget nunca envia um endereço de e-mail ou número de telefone, portanto, um usuário apenas do Telegram no Casdoor não possui nenhum dos dois. Veja o guia do provedor Telegram para os passos do BotFather.

O Telegram agora oferece OpenID Connect também​

A página "Log In With Telegram" do Telegram agora documenta um fluxo padrão OpenID Connect, e a documentação antiga do widget iframe foi movida para uma página de arquivo. Os fatos da documentação do Telegram:

  • Documento de descoberta: https://oauth.telegram.org/.well-known/openid-configuration. Endpoint de autorização https://oauth.telegram.org/auth, endpoint de token https://oauth.telegram.org/token, chaves em https://oauth.telegram.org/.well-known/jwks.json.
  • No @BotFather você abre as configurações do Login Widget do seu bot, registra as URLs permitidas (origens e URIs de redirecionamento exatas) e obtém um client ID e um client secret.
  • Fluxo de código de autorização, PKCE com S256 recomendado. A requisição de token usa autenticação HTTP Basic com o client ID e secret.
  • Scopes: openid é obrigatório; profile adiciona o nome, preferred_username e picture; phone adiciona phone_number com o consentimento do usuário. Não há claim de e-mail.
  • Não existe um endpoint UserInfo. Todos os dados do usuário estão no token de ID, cujo iss é https://oauth.telegram.org e cujo aud é o ID do seu bot.

Você pode conectar esse fluxo com um provedor OAuth personalizado do Casdoor. Defina o Auth URL e o Token URL para os endpoints acima, defina o Scope para openid profile (adicione phone se necessário), ative Enable PKCE e deixe o UserInfo URL vazio. Registre o https://<your-casdoor-host>/callback do Casdoor como uma URL permitida no BotFather. Sem um URL UserInfo, o Casdoor extrai o usuário do token de ID na resposta do token: ele exige sub, rejeita um token expirado e verifica se aud contém o client ID. Sem um mapeamento de usuário, sub se torna o ID do usuário, preferred_username o nome de usuário, name o nome de exibição e picture o avatar, e phone_number preenche o telefone. A página de login do Casdoor reconhece um provedor personalizado cuja URL de autenticação aponta para oauth.telegram.org e mantém o state OAuth curto para ele.

Note que um usuário do Telegram autenticado através do widget e a mesma pessoa autenticada através de OIDC não são automaticamente o mesmo usuário do Casdoor. A identidade do widget é o id numérico, enquanto a identidade OIDC é sub, e os próprios exemplos do Telegram mostram valores diferentes para os dois. Escolha um método por aplicação.

X (Twitter) e Facebook​

Esses dois são OAuth 2.0 comuns, mas cada um tem um detalhe que vale a pena conhecer.

X requer um desafio PKCE em sua URL de autorização OAuth 2.0. O tipo Twitter do Casdoor gera um novo code verifier para cada login, envia o desafio S256 e passa o verifier na troca de token, então não há nada para configurar além do client ID e secret. O Casdoor solicita os scopes users.read tweet.read e lê o usuário de /2/users/me, que fornece o ID do usuário, o handle e o nome de exibição. Ele não solicita um campo de e-mail, então planeje usuários do X sem endereço de e-mail. O guia do provedor Twitter cobre as configurações do app.

Facebook retorna um ID de usuário com escopo de aplicativo: a mesma pessoa tem um ID diferente em cada aplicativo do Facebook, então mudar para um novo aplicativo do Facebook significa que seus usuários não corresponderão aos registros antigos, a menos que você os vincule por e-mail. O Casdoor solicita email,public_profile e lê id, name, picture e email da Graph API. O Facebook omite email quando o perfil não possui um endereço válido. Veja o guia do provedor Facebook.

Como sua aplicação vê tudo isso: OIDC puro​

Sua aplicação nunca se comunica diretamente com Steam, Telegram, X ou Facebook. Ela é um cliente OIDC do Casdoor, configurado uma única vez com o emissor do Casdoor, https://<your-casdoor-host>/.well-known/openid-configuration. Você adiciona os provedores sociais à aplicação do Casdoor na aba Providers, e seus botões aparecem na página de login do Casdoor.

Após qualquer um desses logins, o Casdoor encontra ou cria um usuário do Casdoor e finaliza o fluxo normal de código de autorização com sua aplicação. O token de ID que sua aplicação recebe é assinado pelo Casdoor, e seu sub é o ID do usuário do Casdoor, não o SteamID nem o ID do Telegram. Portanto, sua aplicação não precisa de bibliotecas OpenID 2.0, código HMAC, particularidades PKCE por provedor, nem tratamento especial para usuários sem e-mail. O ID original do provedor é armazenado no usuário do Casdoor, por exemplo, nos campos steam ou telegram, caso você precise dele.

Algumas coisas para planejar:

  • Vinculação de contas. O Casdoor vincula um login social a um usuário existente por e-mail verificado, telefone verificado ou nome de usuário, na ordem definida pela regra de vínculo da aplicação. Steam e Telegram baseado em widget não fornecem e-mail nem telefone, então eles criam um usuário separado, a menos que o usuário vincule o provedor a partir de uma conta já autenticada. Veja como o Casdoor vincula contas.
  • Campos extras de perfil. Provedores que passam dados brutos, como o tipo Steam baseado em Goth e provedores personalizados, podem preencher mais campos do usuário através do mapeamento de usuário.
  • O lado do cliente. Qualquer biblioteca padrão funciona contra o Casdoor. Conectar um cliente OIDC padrão lista os endpoints, e o post SSO Spring Boot com OIDC mostra uma aplicação completa.

Referências​