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.

Configuração Rápida
- Crie um Perfil de Integração (tipo OAuth / SSO, escolha um provedor) em Settings → Integration Profiles
- Obtenha
client_id/client_secretdo console do provedor e cole-os no perfil - 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)
- Vá em Settings → Configurations → OAuth, selecione o perfil na aba daquele provedor e acione Enable
- 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:
| Fluxo | Acionado a partir de | Propósito |
|---|---|---|
login | Botão "Sign in with Google/GitHub/…" | Autentica um usuário existente, ou cai automaticamente para register/connect |
register | Botão "Sign up with…" | Cria uma conta totalmente nova a partir do perfil do provedor |
connect | Account → Linked accounts do usuário logado | Anexa 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:
- 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 - A API do Hedhog assina um
stateno formatohhweb.<app>.<flow>.<sig>(assinado com HMAC,apptem como padrão o sentinelaselfquando nenhumredirectAppé fornecido) e redireciona o navegador para a tela de autorização do provedor, solicitando um únicoredirect_urisem fluxo,{ADMIN_URL}/callback/{provider} - O usuário aprova o acesso no site do provedor
- O provedor redireciona o navegador de volta para
{ADMIN_URL}/callback/{provider}?code=...&state=... - A página dispatcher
/callback/[provider]do admin lê e faz o parse dostate, resolve a origem do app iniciador a partir da configuraçãoapp-urls(exposta viaGET /setting/initial) e encaminha o navegador para${origin}/callback/{provider}/{flow}— que é o próprio admin quando o app éselfou desconhecido - Essa página de fluxo chama
{API_URL}/oauth/{provider}/callback/{flow}?code=...para finalizar a troca - 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.
| Provedor | Redirect 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:
- Vá em Settings → Integration Profiles (
/core/integration/profiles) → New - Escolha Type: OAuth / SSO e Provider:
Google,GitHub,Microsoft,Facebook,Microsoft Entra ID,AppleouLinkedIn - Preencha
client_ideclient_secretdo console do provedor — exceto Entra ID, que também precisa detenant_id, e Apple, que precisa deteam_id,key_ide umaprivate_keyem vez de umclient_secretestático (veja a seção Apple abaixo) - Salve — isso cria uma linha em
integration_profilecom suas credenciais no seu JSONconfig
Depois, para cada provedor que você quiser ativar, vá em Settings → Configurations → OAuth e, na aba daquele provedor:
| Campo | O que ele faz |
|---|---|
<Provider> OAuth Profile | Seletor 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 Scopes | Caixas 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.
Console: console.cloud.google.com
- 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"
- Vá em APIs & Services → Credentials → Create Credentials → OAuth client ID, tipo Web application
- Em Authorized redirect URIs, adicione a única URL de callback da tabela acima
- Copie o Client ID e o Client secret para o
client_id/client_secretdo 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
- Clique em New OAuth App
- Defina a Homepage URL para sua URL de admin ou de marketing
- 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âmetrostate - 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
- New registration → defina Supported account types como Accounts in any organizational directory and personal Microsoft accounts
- Em Authentication → Add a platform → Web, adicione a única redirect URI da tabela acima
- Em Certificates & secrets → New client secret, copie o Value imediatamente — o Azure o oculta depois que você sai da página
- 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.com → Identity → 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:
- Defina Supported account types como Accounts in this organizational directory only (single tenant) — é isso que de fato restringe o login à sua organização
- Copie o Directory (tenant) ID da página Overview para o campo
tenant_iddo 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.
Console: developers.facebook.com
- Create App → tipo Consumer → adicione o produto Facebook Login
- 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
- Em Facebook Login → Settings → Valid OAuth Redirect URIs, adicione a única URL de callback da tabela acima
- 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:
- Em Certificates, Identifiers & Profiles → Identifiers, crie um App ID (se você ainda não tiver) e habilite a capacidade Sign in with Apple nele
- Crie um Services ID — é isso que atua como o
client_iddo OAuth. Habilite Sign in with Apple nele e configure-o, adicionando{API_URL}/oauth/apple/callbackcomo a única Return URL registrada (a Apple só aceita um único redirecionamento fixo, a mesma restrição do GitHub) - Em Keys, crie uma nova chave com Sign in with Apple habilitado, e baixe o arquivo de chave privada
.p8imediatamente — a Apple só permite baixá-lo uma vez - Anote seu Team ID (canto superior direito da conta de desenvolvedor) e o Key ID da chave que você acabou de criar
- Cole
team_id,key_ide o conteúdo do arquivo.p8nos camposteam_id/key_id/private_keydo 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.
Console: linkedin.com/developers/apps
- Create app, associe-o a uma LinkedIn Company Page (exigida pelo LinkedIn até para testes)
- Em Products, solicite "Sign In with LinkedIn using OpenID Connect"
- Em Auth → OAuth 2.0 settings → Authorized redirect URLs, adicione a única URL de callback da tabela acima
- 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:
- O app abre o navegador do sistema em
{ADMIN_URL}/auth/desktop-oauth?provider=<provider>&scheme=<custom-scheme> - Essa página do admin redireciona para o fluxo web normal,
{API_URL}/oauth/<provider>/login— nenhumredirectAppé passado, então o app do state resolve paraselfe o hub (admin) trata o callback localmente - O usuário se autentica com o provedor normalmente e retorna ao app admin, agora logado
- O admin mostra uma tela
/auth/desktopcom um botão Authorize; clicar nele chamaPOST /auth/desktop-tokenpor um novo par de tokens e navega para<scheme>://auth-callback?accessToken=...&refreshToken=... - 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 eventoopen-url(macOS) ousecond-instance(Windows/Linux) - Android/iOS (Expo/React Native) usa o
openAuthSessionAsync(authUrl, '<scheme>://')doexpo-web-browser, que abre uma sessão efêmera de navegador de autenticação e resolve diretamente com a URL de redirecionamento final — parseada comexpo-linking, sem necessidade de um listener de deep-link separado
- Electron se registra como o manipulador do esquema com
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_accountdeve aparecer em vez de um erro
Solução de Problemas
| Sintoma | Causa provável |
|---|---|
Erro redirect_uri_mismatch do provedor | A única redirect URI não foi registrada, ou não corresponde exatamente (barra final, http vs https) |
OAuth provider X is not enabled | O interruptor do provedor está desligado, ou nenhum Perfil de Integração está selecionado, em Settings → Configurations → OAuth |
OAuth callback origin is invalid | Um 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 cadastros | O 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_id | tenant_id não foi preenchido no Perfil de Integração |
Erro AADSTS54005 do Entra ID | O código de autorização já foi resgatado (replay) — peça ao usuário para reiniciar o login |
Erro invalid_client da Apple | team_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 provedor | O app ainda está em modo Testing/Development e o usuário não está na lista de usuários de teste |