Logotipo Hedhog

Receba novidades do Hedhog no seu e-mail

Novos lançamentos, receitas e breaking changes — sem spam.

OAuth / SSO

A biblioteca de autenticação do Hedhog suporta login social e corporativo via OAuth 2.0. Uma vez que um provedor está configurado, os usuários podem entrar, se registrar ou vincular uma conta existente a uma identidade de terceiros com um clique.

Este guia presume que você tenha uma instância do Hedhog em execução e acesso de administrador. Se você acabou de clonar o projeto, as URLs padrão são:

  • Admin (frontend): http://localhost:3200
  • API (backend): http://localhost:3100

Elas mapeiam diretamente para a configuração url (Settings → Configurations → General → System URL), que o Hedhog usa para construir cada URL de redirecionamento OAuth. Atualize-a para o seu domínio real antes de configurar qualquer provedor em produção — toda URL abaixo é derivada dela.

Status: ✅ Totalmente implementado — Google, GitHub, Microsoft, Microsoft Entra ID, Facebook, Apple e LinkedIn funcionam de ponta a ponta, incluindo os fluxos de vinculação de conta login/register/connect. Apps nativos (Electron, Android, iOS) também fazem login pelo mesmo hub, via redirecionamento no navegador do sistema.

Fluxos OAuth de login, register e connect redirecionando pelas páginas de callback do admin até a API do Hedhog

Configuração Rápida

  1. Crie um Perfil de Integração (tipo OAuth / SSO, escolha um provedor) em Settings → Integration Profiles
  2. Obtenha client_id/client_secret do console do provedor e cole-os no perfil
  3. Registre a única URL de callback para aquele provedor naquele console — veja a tabela abaixo (GitHub e Apple usam uma URL de backend fixa em vez disso)
  4. Vá em Settings → Configurations → OAuth, selecione o perfil na aba daquele provedor e acione Enable
  5. Clique em "Sign in with <Provider>" na página de login para confirmar que ele redireciona e conecta você

Como Funciona

O OAuth no Hedhog tem três fluxos distintos, não um:

FluxoAcionado a partir dePropósito
loginBotão "Sign in with Google/GitHub/…"Autentica um usuário existente, ou cai automaticamente para register/connect
registerBotão "Sign up with…"Cria uma conta totalmente nova a partir do perfil do provedor
connectAccount → Linked accounts do usuário logadoAnexa uma identidade de provedor à conta atual sem desconectar

Diferente de muitas configurações OAuth, o Hedhog não registra um redirect URI separado por fluxo. Cada provedor recebe exatamente uma URL de callback, e o fluxo — mais o app que o iniciou — viaja dentro de um parâmetro state assinado. O trajeto de ida e volta:

  1. O navegador abre {API_URL}/oauth/{provider}/login (ou /register, /connect), opcionalmente com um query param ?redirectApp=<key> quando um app não-admin (ex.: training) é quem inicia o fluxo
  2. A API do Hedhog assina um state no formato hhweb.<app>.<flow>.<sig> (assinado com HMAC, app tem como padrão o sentinela self quando nenhum redirectApp é fornecido) e redireciona o navegador para a tela de autorização do provedor, solicitando um único redirect_uri sem fluxo, {ADMIN_URL}/callback/{provider}
  3. O usuário aprova o acesso no site do provedor
  4. O provedor redireciona o navegador de volta para {ADMIN_URL}/callback/{provider}?code=...&state=...
  5. A página dispatcher /callback/[provider] do admin lê e faz o parse do state, resolve a origem do app iniciador a partir da configuração app-urls (exposta via GET /setting/initial) e encaminha o navegador para ${origin}/callback/{provider}/{flow} — que é o próprio admin quando o app é self ou desconhecido
  6. Essa página de fluxo chama {API_URL}/oauth/{provider}/callback/{flow}?code=... para finalizar a troca
  7. A API troca o code por um access token, busca o perfil e emite uma sessão JWT do Hedhog (ou cria/vincula a conta, para register/connect)

Vínculo de origem: quando o app resolvido não é self, a API também exige que o cabeçalho Origin (ou Referer, como fallback) da requisição de callback corresponda à URL registrada daquele app em app-urls — caso contrário, ela rejeita com 400 OAuth callback origin is invalid. É isso que impede que um state forjado redirecione tokens para uma origem arbitrária.

GitHub e Apple são ambos exceções à regra de callback único, por razões diferentes: nenhum deles permite que o Hedhog registre a URL {ADMIN_URL}/callback/{provider} que carrega o fluxo, então ambos sempre redirecionam para uma URL de backend fixa, {API_URL}/oauth/{provider}/callback, e a própria API faz um redirecionamento 302 do navegador adiante para {ADMIN_URL}/callback/{provider}/{flow} para continuar o mesmo fluxo dos outros provedores. A Apple exige adicionalmente response_mode=form_post, então seu endpoint de backend é um POST, não um GET — a API converte esse POST no mesmo desvio baseado em GET internamente.

Você não escreve nada desse código de troca OAuth você mesmo — o OAuthService do @hed-hog/core e as classes por provedor em libraries/core/src/oauth/providers/ cuidam disso.

As Redirect URIs Que Você Realmente Precisa Registrar

Esta é a parte que novos desenvolvedores geralmente erram: parece que há muitas peças móveis (login/register/connect), mas quase todo provedor precisa de apenas uma redirect URI registrada, porque o fluxo viaja no state, não no path.

ProvedorRedirect URI para registrar
Google, Facebook, Microsoft, Entra ID, LinkedIn{ADMIN_URL}/callback/<provider>
GitHub, Apple{API_URL}/oauth/<provider>/callback (URL fixa — o fluxo viaja no state)

Substitua <provider> por google, facebook, microsoft, microsoft-entra-id ou linkedin. Com a configuração local padrão, isso é, por exemplo, para o Google:

http://localhost:3200/callback/google

Se você esquecer de registrar essa URI (ou registrá-la com um esquema/barra final divergente), todo fluxo — não apenas register/connect — vai falhar com um erro "redirect_uri_mismatch" do lado do provedor, já que login, register e connect agora compartilham a mesma URI.

A maioria dos provedores também pede metadados no nível do app que nada têm a ver com o callback — tipicamente uma Homepage URL, uma Privacy Policy URL e uma Terms of Service URL — antes de permitir que você publique o app fora do modo de teste/desenvolvimento. Elas não precisam apontar para nada funcional durante o desenvolvimento; você pode usar seu site de marketing ou até a própria URL do admin, mas apps de produção (especialmente a tela de consentimento "External" do Google e apps do Facebook em modo Live) recusarão a verificação sem os três.

Configurando o Perfil de Integração (todo provedor)

As credenciais OAuth não são armazenadas como configurações simples — elas ficam em um Perfil de Integração genérico, o mesmo mecanismo usado para provedores de e-mail, armazenamento, AI e pagamentos:

  1. Vá em Settings → Integration Profiles (/core/integration/profiles) → New
  2. Escolha Type: OAuth / SSO e Provider: Google, GitHub, Microsoft, Facebook, Microsoft Entra ID, Apple ou LinkedIn
  3. Preencha client_id e client_secret do console do provedor — exceto Entra ID, que também precisa de tenant_id, e Apple, que precisa de team_id, key_id e uma private_key em vez de um client_secret estático (veja a seção Apple abaixo)
  4. Salve — isso cria uma linha em integration_profile com suas credenciais no seu JSON config

Depois, para cada provedor que você quiser ativar, vá em Settings → Configurations → OAuth e, na aba daquele provedor:

CampoO que ele faz
<Provider> OAuth ProfileSeletor de entidade — selecione o Perfil de Integração que você acabou de criar
Enable <Provider>Interruptor — liga/desliga o provedor sem excluir o perfil
OAuth ScopesCaixas de seleção — permissões solicitadas durante o consentimento

Um provedor sem perfil selecionado, ou com o interruptor desligado, retorna 400 OAuth provider X is not enabled se um cliente tentar usá-lo — isso é esperado, não um bug, enquanto você está no meio da configuração.

Há também uma configuração global de Default Role na aba OAuth → General (oauth-role-assignment): papéis concedidos automaticamente a usuários que se registram via qualquer provedor OAuth. Deixe-a vazia para recorrer ao papel padrão do sistema.


Google

Console: console.cloud.google.com

  1. Crie (ou selecione) um projeto, depois vá em APIs & Services → OAuth consent screen. Preencha o nome do app, o e-mail de suporte e as três URLs mencionadas acima (Homepage, Privacy Policy, Terms of Service) — necessárias para tirar o app do status "Testing"
  2. Vá em APIs & Services → Credentials → Create Credentials → OAuth client ID, tipo Web application
  3. Em Authorized redirect URIs, adicione a única URL de callback da tabela acima
  4. Copie o Client ID e o Client secret para o client_id / client_secret do Perfil de Integração

Os escopos solicitados por padrão são email e profile; o Hedhog também chama a People API para gênero/aniversário se concedido, mas isso é opcional e não é necessário para o login funcionar.

Enquanto a tela de consentimento OAuth estiver em modo Testing, apenas os usuários de teste que você adicionar explicitamente podem fazer login — se um usuário real receber "Access blocked: this app's request is invalid", essa é quase sempre a causa.


GitHub

Console: github.com → Settings → Developer settings → OAuth Apps

  1. Clique em New OAuth App
  2. Defina a Homepage URL para sua URL de admin ou de marketing
  3. Defina a Authorization callback URL para {API_URL}/oauth/github/callback — esta é a única URL que o GitHub permite que você registre por app, e é por isso que o Hedhog roteia login, register e connect através dela usando o parâmetro state
  4. Copie o Client ID, depois clique em Generate a new client secret e copie-o imediatamente (o GitHub só o mostra uma vez)

Os escopos padrão são read:user e user:email. Se uma conta GitHub não tiver e-mail público e o compartilhamento de e-mail estiver restrito, o Hedhog recorre a chamar /user/emails para encontrar o endereço primário verificado — certifique-se de que o usuário tem pelo menos um e-mail verificado, ou o registro vai falhar.


Microsoft (Contas pessoais)

Console: portal.azure.com → App registrations

  1. New registration → defina Supported account types como Accounts in any organizational directory and personal Microsoft accounts
  2. Em Authentication → Add a platform → Web, adicione a única redirect URI da tabela acima
  3. Em Certificates & secrets → New client secret, copie o Value imediatamente — o Azure o oculta depois que você sai da página
  4. Copie o Application (client) ID da página Overview

Os escopos padrão são openid, profile, email, User.Read e offline_access (este último é o que permite ao Hedhog solicitar um refresh token).


Microsoft Entra ID (Contas de trabalho / escolares)

Console: entra.microsoft.comIdentity → Applications → App registrations (o centro de administração dedicado do Microsoft Entra — um caminho mais direto do que o Portal do Azure geral para configuração de tenant/app)

Mesmo fluxo de App Registration do Microsoft acima, com duas diferenças:

  1. Defina Supported account types como Accounts in this organizational directory only (single tenant) — é isso que de fato restringe o login à sua organização
  2. Copie o Directory (tenant) ID da página Overview para o campo tenant_id do Perfil de Integração — sem ele, o perfil é rejeitado com "Microsoft Entra ID OAuth profile is missing tenant_id"

A redirect URI usa o slug de provedor microsoft-entra-id: {ADMIN_URL}/callback/microsoft-entra-id.


Facebook

Console: developers.facebook.com

  1. Create App → tipo Consumer → adicione o produto Facebook Login
  2. Em App Settings → Basic, preencha App Domains, Privacy Policy URL e Terms of Service URL — o Facebook não permitirá que o app saia do modo Development sem os três
  3. Em Facebook Login → Settings → Valid OAuth Redirect URIs, adicione a única URL de callback da tabela acima
  4. Copie o App ID e o App secret das configurações Basic

O escopo padrão é apenas email. Enquanto o app está em modo Development, apenas usuários com um papel no app (Admin/Developer/Tester) podem fazer login — adicione usuários de teste em Roles antes de testar com uma conta comum.


Apple (Sign in with Apple)

Console: developer.apple.com/account

A configuração da Apple é a mais complexa dos sete provedores, e ela não usa um client secret estático:

  1. Em Certificates, Identifiers & Profiles → Identifiers, crie um App ID (se você ainda não tiver) e habilite a capacidade Sign in with Apple nele
  2. Crie um Services ID — é isso que atua como o client_id do OAuth. Habilite Sign in with Apple nele e configure-o, adicionando {API_URL}/oauth/apple/callback como a única Return URL registrada (a Apple só aceita um único redirecionamento fixo, a mesma restrição do GitHub)
  3. Em Keys, crie uma nova chave com Sign in with Apple habilitado, e baixe o arquivo de chave privada .p8 imediatamente — a Apple só permite baixá-lo uma vez
  4. Anote seu Team ID (canto superior direito da conta de desenvolvedor) e o Key ID da chave que você acabou de criar
  5. Cole team_id, key_id e o conteúdo do arquivo .p8 nos campos team_id / key_id / private_key do Perfil de Integração (o client_id é o identificador do Services ID)

Diferente de todos os outros provedores, o Hedhog não armazena um client_secret estático para a Apple — ele cunha um JWT novo, assinado com ES256, a partir de team_id/key_id/private_key em cada troca de token, válido por 5 minutos. Não há nada para rotacionar ou expirar do seu lado.

A Apple também exige response_mode=form_post, então o redirecionamento de volta é um POST do navegador, não um GET — o endpoint /oauth/apple/callback do Hedhog trata disso e o converte no mesmo fluxo dos outros provedores. Os escopos padrão são name e email, mas a Apple só envia o nome do usuário na primeira autorização de todas — se ele estiver ausente em um login posterior, o Hedhog recorre à parte local do endereço de e-mail.


LinkedIn

Console: linkedin.com/developers/apps

  1. Create app, associe-o a uma LinkedIn Company Page (exigida pelo LinkedIn até para testes)
  2. Em Products, solicite "Sign In with LinkedIn using OpenID Connect"
  3. Em Auth → OAuth 2.0 settings → Authorized redirect URLs, adicione a única URL de callback da tabela acima
  4. Copie o Client ID e o Client Secret da aba Auth

Os escopos padrão são openid, profile e email. Os dados de perfil vêm de uma única chamada OIDC a /v2/userinfo — o antigo esquema de duas chamadas /v2/me + /v2/emailAddress do LinkedIn não é usado.


OAuth a Partir de Apps Nativos (Android, iOS, Electron)

Apps nativos (o app de desktop Electron, e Android/iOS via Expo/React Native) não conversam com os provedores OAuth diretamente — eles reutilizam exatamente o mesmo hub web descrito acima, abrindo um navegador do sistema (não uma WebView embutida) e capturando o redirecionamento final através de um esquema de URI personalizado:

  1. O app abre o navegador do sistema em {ADMIN_URL}/auth/desktop-oauth?provider=<provider>&scheme=<custom-scheme>
  2. Essa página do admin redireciona para o fluxo web normal, {API_URL}/oauth/<provider>/login — nenhum redirectApp é passado, então o app do state resolve para self e o hub (admin) trata o callback localmente
  3. O usuário se autentica com o provedor normalmente e retorna ao app admin, agora logado
  4. O admin mostra uma tela /auth/desktop com um botão Authorize; clicar nele chama POST /auth/desktop-token por um novo par de tokens e navega para <scheme>://auth-callback?accessToken=...&refreshToken=...
  5. O app nativo intercepta essa URL de esquema personalizado e extrai os tokens:
    • Electron se registra como o manipulador do esquema com app.setAsDefaultProtocolClient('hedhog'), depois lê a URL do evento open-url (macOS) ou second-instance (Windows/Linux)
    • Android/iOS (Expo/React Native) usa o openAuthSessionAsync(authUrl, '<scheme>://') do expo-web-browser, que abre uma sessão efêmera de navegador de autenticação e resolve diretamente com a URL de redirecionamento final — parseada com expo-linking, sem necessidade de um listener de deep-link separado

Todo app nativo precisa do seu próprio esquema personalizado registrado — configurado via a opção protocols do electron-builder para Electron, ou o campo scheme no app.json para apps Expo (ex.: hedhog://, hedhogoperations://, hedhoginbox://). Não há universal links / Android App Links envolvidos — apenas o esquema personalizado.


Verifique se Funcionou

  • Clique em "Sign in with <Provider>" — você deve chegar na tela de consentimento do provedor, depois voltar por /callback/<provider> e acabar logado
  • Tente o mesmo fluxo com uma conta que nunca se registrou antes — ela deve se auto-registrar em vez de falhar
  • Se você suporta vinculação de contas, faça login com um método diferente, vá em Account → Linked accounts e conecte o provedor — uma nova linha user_account deve aparecer em vez de um erro

Solução de Problemas

SintomaCausa provável
Erro redirect_uri_mismatch do provedorA única redirect URI não foi registrada, ou não corresponde exatamente (barra final, http vs https)
OAuth provider X is not enabledO interruptor do provedor está desligado, ou nenhum Perfil de Integração está selecionado, em Settings → Configurations → OAuth
OAuth callback origin is invalidUm app não-admin (ex.: training) iniciou o fluxo via redirectApp, mas sua origem não está registrada na configuração app-urls, ou o Origin/Referer da requisição não corresponde a ela
Funciona para login mas não para novos cadastrosO próprio provedor está bloqueando novas contas (ex.: restrições do modo Testing/Development) — a redirect URI é compartilhada entre os três fluxos agora, então raramente é um problema de URI ausente
Microsoft Entra ID OAuth profile is missing tenant_idtenant_id não foi preenchido no Perfil de Integração
Erro AADSTS54005 do Entra IDO código de autorização já foi resgatado (replay) — peça ao usuário para reiniciar o login
Erro invalid_client da Appleteam_id, key_id ou private_key no Perfil de Integração não correspondem ao Services ID/chave no console de desenvolvedor da Apple
Usuário preso para sempre na tela de consentimento do provedorO app ainda está em modo Testing/Development e o usuário não está na lista de usuários de teste