> ## Documentation Index
> Fetch the complete documentation index at: https://docs.userkit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Login social

> Google, na sua própria tela de consentimento — e as regras de vinculação que impedem isso de virar um sequestro de conta.

Login social são duas chamadas, porque o redirecionamento sai do nosso processo:
**start** devolve a URL para onde mandar o navegador, **callback** gasta o código
que o provedor devolveu.

Ambas são endpoints de modo hosted alcançados com uma chave publicável, a partir
do seu próprio domínio. Nada anda em cookie: o `state` volta para você, e
apresentá-lo no callback é o que prova que as duas metades são o mesmo fluxo.

<Note>
  Google hoje. Adicionar um provedor é uma linha e uma implementação do nosso lado
  — nunca uma migração, e nunca uma mudança nas duas chamadas abaixo.
</Note>

## A aplicação OAuth é sua

Você registra a aplicação no console do Google e guarda as credenciais conosco.
A tela de consentimento que seu cliente lê passa a dizer o nome do **seu**
produto, não o nosso — um provedor de identidade cuja marca aparece na tela de
login dos outros está vendendo a coisa errada.

```bash theme={null}
curl -s -X PUT $API/v1/organization/environments/$ENV_ID/oauth/google \
  -H "Authorization: Bearer uk_st_…" \
  -H "X-Organization-Id: $ORG_ID" \
  -H 'Content-Type: application/json' \
  -d '{ "client_id": "…apps.googleusercontent.com", "client_secret": "…" }'
```

O segredo é cifrado em repouso e **nunca é devolvido**. Você o colou de um
console que administra; um segredo que se lê de volta no painel é um segredo com
mais uma saída. Colá-lo de novo é como se faz a rotação.

Por ambiente, então você pode apontar o de teste para um projeto descartável do
Google e subir com o de verdade.

<Note>
  Um ambiente de **teste** sem nada configurado pode cair numa aplicação
  compartilhada do UserKit, para o login social funcionar nos seus primeiros dez
  minutos. O ambiente live nunca cai: aquela tela de consentimento tem que ser sua.
</Note>

Sua redirect URI precisa estar registrada no Google, como de costume. Ela também
passa pelo nosso próprio portão — a origem dela precisa estar na lista de origens
permitidas da chave publicável sempre que essa lista existir.

Sua tela de login não precisa ser avisada de nada disso. O
`GET /v1/config/{chave}` responde com os provedores com os quais este ambiente de
fato consegue autenticar alguém, então o botão aparece quando você registra a
aplicação — e não no seu próximo deploy. Veja
[Modos de autenticação](/pt-br/customer-auth/modes#lendo-isso-de-uma-tela-de-login).

## Start

```bash theme={null}
curl -s $API/v1/contact-auth/oauth/google/start \
  -H 'Content-Type: application/json' \
  -d '{
    "publishable_key": "uk_pk_live_…",
    "redirect_uri": "https://app.example.com/auth/callback",
    "anonymous_id": "anon_2f9c1b"
  }'
```

```json 200 theme={null}
{
  "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth?…",
  "state": "uk_os_…",
  "expires_at": "2026-07-29T12:15:00Z"
}
```

Mande o navegador para `authorization_url` e guarde o `state` onde a página de
callback consiga ler — session storage é a resposta de sempre. O fluxo vale
quinze minutos.

PKCE é aplicado em todo fluxo, e o verifier nunca sai do nosso processo: o código
de autorização passa por uma página que não controlamos, então um código roubado
sozinho não compra nada.

Passar `anonymous_id` funde o visitante que essa pessoa já era na conta,
atribuição incluída.

Rate limit de 30 por hora por IP.

## Callback

Sua página de redirecionamento recebe `?code=…` e o envia de volta com o state
que guardou:

```bash theme={null}
curl -s $API/v1/contact-auth/oauth/google/callback \
  -H 'Content-Type: application/json' \
  -d '{
    "publishable_key": "uk_pk_live_…",
    "state": "uk_os_…",
    "code": "4/0Ab…"
  }'
```

```json 200 theme={null}
{
  "contact": { "id": "…", "name": "Grace Hopper", "email_verified": true },
  "token": "uk_ct_…",
  "expires_at": "2026-08-28T12:00:00Z",
  "verified": true
}
```

O mesmo formato de um login por senha, para o seu SDK ter uma resposta só,
independente de por onde a pessoa chegou. Autenticar no provedor prova a conta,
então a sessão é verificada.

O state é de uso único e preso ao seu provedor e ao seu ambiente. Desconhecido,
expirado, já gasto e "o provedor recusou o código" respondem todos o mesmo
`401 invalid_grant`. Um provedor que não conseguimos alcançar responde
`502 provider_unavailable` — essa não é culpa de quem chamou.

Rate limit de 30 por hora por IP.

## Como a conta é resolvida

Esta é a parte que vale ler duas vezes. Em ordem:

<Steps>
  <Step title="Um contato já vinculado a esta conta do provedor">
    Resolvido pelo subject id estável do provedor, nunca pelo e-mail. Quem trocou
    o endereço do Google continua sendo a mesma pessoa.
  </Step>

  <Step title="O provedor atestou o endereço">
    Vincula ao contato dono daquele endereço, ou cria um. Duas partes já
    provaram o mesmo endereço, e é isso que torna a vinculação admissível.
  </Step>

  <Step title="O provedor não atestou">
    A conta do provedor é a única identidade que o login carrega. O e-mail entra
    como atributo e não resolve para nada — um contato novo, mesmo que o endereço
    pareça conhecido.
  </Step>
</Steps>

<Warning>
  O passo dois tem um caso por baixo. Se o contato dono do endereço **nunca o
  tinha provado** — cadastrou-se com senha e nunca clicou no link de verificação —
  então a senha nele também nunca foi provada. Ela é removida, junto com todas as
  sessões e todos os tokens de uso único pendentes, e a caixa de entrada é avisada
  do que aconteceu.

  É o sequestro clássico fechado: cadastrar-se com o endereço de outra pessoa,
  esperar que ela chegue pelo Google e herdar a conta dela. Aqui, a credencial não
  provada não sobrevive à conta cujo dono acabou de tomar posse dela.
</Warning>

Vincular nunca é silencioso. Quando uma conta social pousa num contato que já
existia, um aviso vai para o endereço — só quem tem aquela caixa de entrada pode
dizer se foi ele mesmo.

## Removendo um provedor

```bash theme={null}
curl -s -X DELETE $API/v1/organization/environments/$ENV_ID/oauth/google \
  -H "Authorization: Bearer uk_st_…" \
  -H "X-Organization-Id: $ORG_ID"
```

Os vínculos existentes sobrevivem. Eles são histórico, e quem registrar de novo
amanhã não deveria encontrar seus clientes trancados do lado de fora.
