# auth.md

Este documento segue a estrutura do roteiro auth.md publicado pelo WorkOS para registro de agentes em APIs protegidas por OAuth (descobrir, escolher método, registrar, reivindicar, trocar, usar, erros e revogação). Cada seção responde com o que existe em brasilgeo.ai.

Resumo para agentes: este domínio publica um servidor de autorização OAuth 2.1 e uma única capacidade que exige credencial, o pedido de diagnóstico de presença em IA. Tudo o mais continua público e de leitura, sem cabeçalho Authorization. A credencial nasce de uma pessoa: o fluxo é authorization code com PKCE, e a posse do endereço de e-mail é provada por link enviado para a caixa da própria pessoa. Não existe client_credentials aqui, porque não existe capacidade que dispense titular humano.

## Passo 1. Descobrir

### 1a. Metadados do recurso protegido

Cada recurso tem o seu documento RFC 9728, e o campo `resource` é idêntico ao identificador em que o sufixo well-known foi inserido. São três:

- Origem inteira: https://brasilgeo.ai/.well-known/oauth-protected-resource
- Servidor MCP: https://brasilgeo.ai/.well-known/oauth-protected-resource/api/mcp
- Pedido de diagnóstico: https://brasilgeo.ai/.well-known/oauth-protected-resource/api/agentes/diagnostico

O documento do recurso protegido do diagnóstico:

```json
{
  "resource": "https://brasilgeo.ai/api/agentes/diagnostico",
  "resource_name": "Pedido de diagnóstico de presença em IA (Brasil GEO)",
  "authorization_servers": [
    "https://brasilgeo.ai"
  ],
  "scopes_supported": [
    "diagnostico:solicitar"
  ],
  "bearer_methods_supported": [
    "header"
  ],
  "resource_signing_alg_values_supported": [
    "ES256"
  ],
  "resource_documentation": "https://brasilgeo.ai/auth.md",
  "resource_policy_uri": "https://brasilgeo.ai/ai-policy.txt"
}
```

Quando falta o Bearer, a resposta 401 traz `WWW-Authenticate: Bearer resource_metadata="..."` apontando para o documento do recurso pedido, e não para o de outro recurso.

### 1b. Metadados do servidor de autorização

O documento RFC 8414 está em https://brasilgeo.ai/.well-known/oauth-authorization-server. O `issuer` é https://brasilgeo.ai, sem barra final, idêntico caractere a caractere ao valor de `authorization_servers` nos documentos de recurso. Ele carrega o bloco `agent_auth` do roteiro auth.md:

```json
{
  "issuer": "https://brasilgeo.ai",
  "authorization_endpoint": "https://brasilgeo.ai/oauth/authorize",
  "token_endpoint": "https://brasilgeo.ai/oauth/token",
  "registration_endpoint": "https://brasilgeo.ai/oauth/register",
  "revocation_endpoint": "https://brasilgeo.ai/oauth/revoke",
  "jwks_uri": "https://brasilgeo.ai/oauth/jwks.json",
  "scopes_supported": [
    "diagnostico:solicitar"
  ],
  "response_types_supported": [
    "code"
  ],
  "response_modes_supported": [
    "query"
  ],
  "grant_types_supported": [
    "authorization_code"
  ],
  "code_challenge_methods_supported": [
    "S256"
  ],
  "token_endpoint_auth_methods_supported": [
    "none"
  ],
  "revocation_endpoint_auth_methods_supported": [
    "none"
  ],
  "client_id_metadata_document_supported": true,
  "authorization_response_iss_parameter_supported": true,
  "service_documentation": "https://brasilgeo.ai/auth.md",
  "ui_locales_supported": [
    "pt-BR"
  ],
  "resource": "https://brasilgeo.ai",
  "authorization_servers": [
    "https://brasilgeo.ai"
  ],
  "bearer_methods_supported": [
    "header"
  ],
  "agent_auth": {
    "skill": "https://brasilgeo.ai/auth.md",
    "register_uri": "https://brasilgeo.ai/oauth/register",
    "claim_uri": "https://brasilgeo.ai/oauth/authorize",
    "identity_types_supported": [
      "identity_assertion"
    ],
    "identity_assertion": {
      "assertion_types_supported": [
        "verified_email"
      ],
      "credential_types_supported": [
        "access_token"
      ]
    },
    "verified_email": {
      "ceremony": "authorization_code_pkce",
      "verification": "magic_link",
      "login_hint_supported": true,
      "human_interaction_required": true
    }
  }
}
```

O que mais existe para descoberta:

- Catálogo de APIs (RFC 9727): https://brasilgeo.ai/.well-known/api-catalog
- Descrição OpenAPI 3.1 das rotas públicas: https://brasilgeo.ai/openapi.json
- Servidor MCP de leitura (JSON-RPC 2.0 sobre Streamable HTTP): https://brasilgeo.ai/api/mcp, com cartão em https://brasilgeo.ai/api/mcp/server-card
- Habilidades com SHA-256 dos bytes servidos: https://brasilgeo.ai/.well-known/agent-skills/index.json
- AI Catalog e manifesto ARD: https://brasilgeo.ai/.well-known/ai-catalog.json e https://brasilgeo.ai/.well-known/ard.json
- Documentação da integração: https://brasilgeo.ai/agents.md

## Passo 2. Escolher um método

Um método só: `verified_email`. O bloco `agent_auth` declara `identity_types_supported: ["identity_assertion"]` e `identity_assertion.assertion_types_supported: ["verified_email"]`. A cerimônia é `authorization_code_pkce` e a verificação é `magic_link`, com interação humana obrigatória. Não há `service_auth` nem acesso anônimo com credencial: sem titular, use as rotas públicas descritas adiante.

## Passo 3. Registrar

Duas formas, ambas sem segredo de cliente (`token_endpoint_auth_method: "none"`):

1. Client ID Metadata Document, o caminho preferido e anunciado em `client_id_metadata_document_supported`. O `client_id` é a URL https do seu próprio documento de metadados, servido por você em JSON com `client_id` igual à URL e `redirect_uris`. Nada é gravado aqui antes do primeiro uso, e o documento é relido conforme o seu Cache-Control, entre 5 minutos e 24 horas.
2. Registro dinâmico RFC 7591 em POST https://brasilgeo.ai/oauth/register, com corpo JSON contendo `redirect_uris` e, de preferência, `client_name`. A resposta 201 devolve o `client_id` emitido. Cada `redirect_uri` precisa ser https, ou http em 127.0.0.1, [::1] ou localhost, sem fragmento e sem credencial embutida. O registro vale 180 dias e renova a cada uso.

## Passo 4. Cerimônia de reivindicação

GET https://brasilgeo.ai/oauth/authorize com `response_type=code`, `client_id`, `redirect_uri`, `code_challenge`, `code_challenge_method=S256` e, quando quiser restringir a audiência do token, `resource`. Os parâmetros `scope`, `state` e `login_hint` são aceitos. PKCE com S256 é obrigatório: pedido sem `code_challenge` volta ao cliente como `invalid_request`.

A pessoa vê uma tela de consentimento que nomeia o aplicativo, o destino do retorno e o escopo pedido, informa o e-mail e resolve o desafio antiautomação. O servidor envia um link de confirmação para esse endereço, válido por 15 minutos e de uso único. Ao abrir o link e confirmar, o navegador volta para a `redirect_uri` registrada com `code` e `state`. O código dura 2 minutos.

O escopo disponível é `diagnostico:solicitar`. Escopo desconhecido volta como `invalid_scope`.

## Passo 5. Trocar a asserção

POST https://brasilgeo.ai/oauth/token com `Content-Type: application/x-www-form-urlencoded` e os campos `grant_type=authorization_code`, `code`, `code_verifier`, `client_id` e `redirect_uri`. O único grant aceito é `authorization_code`.

A resposta 200 devolve `access_token`, `token_type: "Bearer"`, `expires_in` (3600 segundos, ou 60 minutos) e `scope`. O token é um JWT assinado em ES256, verificável pela chave pública em https://brasilgeo.ai/oauth/jwks.json. Não há refresh token: terminada a hora, a pessoa autoriza de novo.

O código é de uso único. Apresentá-lo duas vezes revoga o token que a primeira apresentação emitiu, como a RFC 9700 manda.

## Passo 6. Usar o access_token

Envie `Authorization: Bearer <token>` para a capacidade protegida:

POST https://brasilgeo.ai/api/agentes/diagnostico, com `Content-Type: application/json` e corpo `{"empresa": "...", "site": "https://...", "mensagem": "..."}`. A resposta 201 devolve `id`, `status`, o e-mail verificado e a confirmação de que a Brasil GEO responde por e-mail a esse endereço.

O token só é lido do cabeçalho Authorization: query string e corpo são ignorados por desenho. Um token emitido para outro recurso é recusado com 401, mesmo válido e assinado. Não envie este token para outro domínio, e não envie credenciais de terceiros para este.

## Como usar as APIs sem credencial

- GET https://brasilgeo.ai/api/articles devolve a lista de artigos publicados (slug, data e URL), em JSON.
- POST https://brasilgeo.ai/api/mcp com Content-Type: application/json e Accept: application/json, text/event-stream aceita initialize, ping, tools/list, tools/call e notifications/initialized. Após initialize, envie MCP-Protocol-Version com a versão negociada (2025-11-25 ou 2025-06-18). São 14 ferramentas de leitura: 9 com arguments vazio e 5 com argumentos declarados no inputSchema (buscarNoAcervo, obterPagina, obterPergunta, buscarNoPortalLeadlovers, consultarGrafoLeadlovers). A compatibilidade REST aceita o corpo {"tool":"getOrganization"} sem os cabeçalhos do MCP.
- Páginas editoriais públicas aceitam Accept: text/markdown e devolvem a representação derivada do mesmo HTML.
- Nas páginas públicas, o navegador carrega /assets/webmcp.js, que registra ferramentas WebMCP de leitura apoiadas nesses mesmos endpoints.

Limites vigentes, lidos do código do Worker:

- 60 requisições por minuto por endereço IP em /api/*, com exceção de /api/health. Ao exceder, a resposta é 429 com Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset. A janela é fixa, de 60 segundos.
- Corpo da requisição ao MCP limitado a 16 KiB (16.384 bytes); acima disso a resposta é 413 e a leitura do corpo é cancelada.
- Corpo das requisições OAuth e do pedido de diagnóstico limitado a 8 KiB (8.192 bytes).
- Quando o cabeçalho Origin está presente em /api/mcp, apenas https://brasilgeo.ai e https://www.brasilgeo.ai são aceitos; outras origens recebem 403.
- Os formulários de contato e de newsletter exigem um token antispam de uso único emitido ao navegador e não são canal para agentes.

## Erros

| Resposta | Situação | O que fazer |
| --- | --- | --- |
| 401 com WWW-Authenticate | sem Bearer, token inválido, expirado, revogado ou emitido para outro recurso | siga o resource_metadata do cabeçalho e refaça os passos 4 e 5 |
| 403 insufficient_scope | token válido sem o escopo diagnostico:solicitar | peça o escopo no passo 4 e obtenha um token novo |
| 400 invalid_grant | código expirado, já usado, de outro cliente ou code_verifier que não confere | reinicie em https://brasilgeo.ai/oauth/authorize |
| 400 invalid_request no authorize | falta code_challenge, método diferente de S256 ou parâmetro repetido | corrija o pedido; PKCE S256 é obrigatório |
| 400 invalid_target | resource fora dos recursos deste servidor | use um dos identificadores listados no passo 1a |
| 503 temporarily_unavailable | chave de assinatura indisponível no momento | aguarde o Retry-After e repita |
| 429 rate_limited ou rate_limit_exceeded | mais de 60 requisições por minuto do mesmo IP em /api/*, ou excesso de pedidos nos endpoints OAuth | aguardar o valor de Retry-After e repetir |
| 413 request_too_large | corpo do MCP acima de 16 KiB, ou corpo OAuth acima de 8 KiB | reduzir o corpo; as ferramentas de leitura não recebem argumentos |
| 403 origin_not_allowed | Origin fora de brasilgeo.ai em /api/mcp | chamar sem Origin ou a partir do próprio domínio |
| 400 invalid_json, missing_tool ou unsupported_protocol_version | corpo inválido, sem o campo tool ou versão MCP não aceita | corrigir o envelope; consulte GET /api/mcp ou tools/list |
| 404 unknown_tool | ferramenta inexistente | usar um dos nomes listados em available |
| 401 ou 403 em documentos restritos e em /api/admin/ | conteúdo fora do escopo público | não há caminho automatizado; use o contato humano |

## Revogação

POST https://brasilgeo.ai/oauth/revoke com `token` no corpo, conforme a RFC 7009. A resposta é 200 tanto para token revogado quanto para token que nunca existiu: quem chama não descobre a diferença. Token emitido a outro cliente é recusado com `unauthorized_client`.

Não há credencial de longa duração para revogar em massa: o token vale 60 minutos e não existe refresh token. Mudanças na política de acesso são publicadas em https://brasilgeo.ai/ai-policy.txt e em https://brasilgeo.ai/robots.txt.

## Documentos restritos e contato

Roadmaps e documentos sob acordo de confidencialidade permanecem protegidos por senha e fora dos sitemaps, do MCP e da negociação Markdown. Não há caminho automatizado para obtê-los, e o escopo diagnostico:solicitar não dá acesso a eles. Pedidos humanos: contato@brasilgeo.ai.

Última revisão: 18 de setembro de 2026.
