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

# OAuth

> Implemente OAuth 2.0 com PKCE na Cardápio Web: autorização no portal, troca de token, escopos, refresh, Bearer na API aberta e erros comuns.

Apps da CW App Store autenticam-se via **OAuth 2.0 Authorization Code com PKCE**. Após o Proprietário autorizar no portal e a integradora concluir a **troca de token** no servidor, o app recebe credenciais para consumir a API aberta.

<Note>
  Entenda também a [instalação e
  autorização](/cw-app-store/instalacao-e-autorizacao) do ponto de vista do
  estabelecimento e da integradora.
</Note>

<Warning>
  Somente usuários com perfil **Proprietário** podem autorizar a instalação de
  um app no portal. Ao redirecionar o cliente para a página de autorização do
  portal CW, confirme que ele está logado com a conta de **Proprietário** do
  estabelecimento. Outros perfis recebem `access_denied`.
</Warning>

## Endpoints

O fluxo OAuth usa **dois hosts distintos**: o **portal CW** (frontend) para autorização e a **API aberta** para troca e renovação de tokens. Use sempre o par do **mesmo ambiente** (Sandbox ou Produção).

### Autorização (portal CW)

Após o onboarding, redirecione o Proprietário para a página de autorização do portal no ambiente em que o app está cadastrado:

| Ambiente     | URL de autorização                               |
| ------------ | ------------------------------------------------ |
| **Sandbox**  | `https://portal.sandbox.cardapioweb.com/cw-apps` |
| **Produção** | `https://portal.cardapioweb.com/cw-apps`         |

### Troca e renovação de token (API)

| Método | Path                       | Descrição                                      |
| ------ | -------------------------- | ---------------------------------------------- |
| POST   | `/api/partner/oauth/token` | Troca código ou refresh token por access token |

| Ambiente     | Base URL da API                              |
| ------------ | -------------------------------------------- |
| **Sandbox**  | `https://integracao.sandbox.cardapioweb.com` |
| **Produção** | `https://integracao.cardapioweb.com`         |

Os exemplos abaixo usam o **Sandbox**; substitua os hosts ao integrar em Produção. Detalhes dos ambientes em [Sobre a API](/sobre-a-api#ambiente-de-testes-e-de-producao).

Referência interativa na aba **Referência da API**:

* [Obter token](/api-reference/autenticacao/oauth/obter-token)

## Fluxo resumido

```mermaid theme={null}
sequenceDiagram
  participant App as App parceiro
  participant Portal as Portal CW
  participant Owner as Proprietário do estabelecimento
  participant API as API Cardápio Web

  App->>Portal: redirect portal CW + PKCE
  Portal->>Owner: Tela de consentimento
  Owner->>Portal: Autoriza instalação
  Portal->>App: redirect com code
  App->>API: POST /api/partner/oauth/token + code_verifier
  API->>App: access_token + refresh_token
  App->>API: API aberta com Bearer
```

## 1. Gerar PKCE

Antes de redirecionar o Proprietário para a página de autorização do portal CW (`https://portal.cardapioweb.com/cw-apps`), gere:

* `code_verifier`: string aleatória (43–128 caracteres)
* `code_challenge`: Base64 URL-safe do SHA-256 do `code_verifier`
* `code_challenge_method`: `S256`

Guarde o `code_verifier` para a troca de token.

Exemplo com OpenSSL:

```bash theme={null}
CODE_VERIFIER=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | tr -d '=')
```

## 2. Autorização

Após o onboarding na **URL de instalação** do app, redirecione o **Proprietário** para a página de autorização do portal CW (`https://portal.cardapioweb.com/cw-apps`) com:

| Parâmetro               | Quem gera   | Descrição                                                                     |
| ----------------------- | ----------- | ----------------------------------------------------------------------------- |
| `client_id`             | CW          | Identificador público do app na CW App Store.                                 |
| `state`                 | Integradora | Parâmetro de correlação; o portal devolve o mesmo valor no callback.          |
| `redirect_uri`          | Integradora | Deve ser **idêntica** à Redirect URI informada ao suporte no cadastro do app. |
| `code_challenge`        | Integradora | Derivado do `code_verifier` (SHA-256 + Base64 URL-safe).                      |
| `code_challenge_method` | Fixo        | Sempre `S256`.                                                                |

Exemplo de URL (Sandbox):

```
https://portal.sandbox.cardapioweb.com/cw-apps
  ?client_id=SEU_CLIENT_ID
  &state=usr_abc123
  &redirect_uri=https://seuapp.com/oauth/callback
  &code_challenge=CHALLENGE
  &code_challenge_method=S256
```

### Sobre o `state`

O `state` é um **parâmetro de correlação** que você envia no início do fluxo e recebe de volta no redirect para a `redirect_uri` (`?code=...&state=...`). Serve para retomar o contexto daquela autorização no seu sistema.

**Exemplo:** durante o onboarding, o Proprietário está vinculado ao usuário interno `usr_abc123` no seu sistema. Ao redirecionar para `https://portal.cardapioweb.com/cw-apps`, envie `state=usr_abc123` (ou um token opaco que mapeie para esse usuário). Quando o portal redirecionar de volta para a Redirect URI com o mesmo `state`, você saberá **para qual usuário** aquela autorização foi concluída.

**Recomendações:**

* Gere e persista o `state` no **backend** antes do redirect (não confie apenas em estado no frontend).
* No callback, valide que o `state` retornado é um valor que **você emitiu** e que ainda está válido (expiração, uso único, etc.).
* Pode ser um ID interno, um UUID ou um valor opaco assinado. O importante é permitir identificar o contexto da instalação no seu lado.

<Warning>
  **Não envie** `code_verifier` na URL. Ele permanece **somente no servidor** da
  integradora até o `POST /api/partner/oauth/token`. Valide o `state` recebido no callback
  antes de trocar o código por tokens.
</Warning>

### O que o portal faz

O portal CW conduz a autorização e redireciona para sua Redirect URI. Você **não implementa** estas etapas:

* Verifica o login do Proprietário; se necessário, redireciona ao login e retorna à página de autorização com os mesmos parâmetros.
* Exibe o consentimento (app, loja, permissões).
* Redireciona o navegador para a `redirect_uri` com `?code=...&state=...`.

## 3. Troca de token

Apps de integradoras são **clientes públicos**: não há segredo no fluxo de instalação. A segurança vem do **PKCE** e da troca de token feita **no servidor** da integradora.

Os passos de PKCE e redirect ao portal estão nas seções [Gerar PKCE](#1-gerar-pkce) e [Autorização](#2-autorizacao). **A partir do callback** na Redirect URI:

<Steps>
  <Step title="1. Receber o callback">
    A Redirect URI recebe `code` e `state` na query string. A autorização foi concedida, mas a integração **ainda não está ativa**.
  </Step>

  <Step title="2. Validar o state">
    Confirme que o `state` retornado é um valor que você emitiu e que ainda está válido.
  </Step>

  <Step title="3. Trocar o código no servidor">
    No **servidor**, chame `POST /api/partner/oauth/token` com `grant_type=authorization_code`, o `code`, o mesmo `redirect_uri`, o `client_id` e o `code_verifier`.
  </Step>

  <Step title="4. Persistir por loja">
    Armazene `access_token` e `refresh_token` vinculados à **instalação** (contexto da loja autorizada). Cada loja gera tokens próprios.
  </Step>
</Steps>

Exemplo de requisição (Sandbox):

```bash theme={null}
curl -X POST https://integracao.sandbox.cardapioweb.com/api/partner/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=CODIGO_RECEBIDO" \
  -d "redirect_uri=https://seuapp.com/oauth/callback" \
  -d "client_id=SEU_CLIENT_ID" \
  -d "code_verifier=SEU_CODE_VERIFIER"
```

Resposta esperada:

```json theme={null}
{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 7200,
  "refresh_token": "...",
  "scope": "store orders"
}
```

O `access_token` expira em **2 horas** (`expires_in`: 7200 segundos). Com a troca bem-sucedida, a instalação fica **ativa** e a Partner API e os webhooks passam a operar para aquela loja.

## 4. Escopos e permissões

Com OAuth, as **permissões** do app vêm **inteiramente do cadastro** informado ao suporte. A integradora **não escolhe** nem envia escopos na URL de autorização: o portal concede **todas** as permissões cadastradas no consentimento. Tokens só acessam endpoints cujo escopo está presente no token **e** na instalação ativa.

### Escopos disponíveis

| Escopo      | Recursos                                 | Módulo da API                                                         |
| ----------- | ---------------------------------------- | --------------------------------------------------------------------- |
| `store`     | Dados da loja e formas de pagamento      | [Consultar loja](/api-reference/loja/loja/consultar-loja)             |
| `orders`    | Consulta, criação e alteração de pedidos | [API Pedidos](/api-reference/pedidos/polling-de-pedidos)              |
| `catalog`   | Consulta e gestão do catálogo            | [API Catálogo](/api-reference/catalogo/consultar-catalogo-completo)   |
| `customers` | Clientes do estabelecimento              | [Listar clientes](/api-reference/loja/clientes/listar-clientes)       |
| `coupons`   | Cupons de desconto                       | [Listar cupons](/api-reference/loja/cupons/listar-cupons)             |
| `reviews`   | Avaliações                               | [Listar avaliações](/api-reference/loja/avaliacoes/listar-avaliacoes) |

### Como funcionam

1. No [cadastro do app](/cw-app-store/cadastro-e-publicacao), informe ao suporte as **permissões** necessárias.
2. Na instalação, o Proprietário autoriza todas as permissões cadastradas no portal.
3. O token OAuth recebe os escopos concedidos naquela instalação.
4. A API aberta valida o escopo do token e o estado atual da instalação.

<Note>
  Solicite apenas os escopos que seu app realmente usa. Permissões excedidas
  dificultam aprovação e reduzem a confiança do restaurante.
</Note>

Se precisar de **novas permissões** após o app já estar publicado, solicite a alteração ao suporte. Lojas já instaladas precisam **reinstalar** o app para que os novos escopos passem a valer.

Se o token não possui o escopo exigido pelo endpoint, a API retorna **HTTP 403**.

Autenticação por `X-API-KEY` **não** aplica escopos. Veja [API Key (legado)](/autenticacao/api-key-legado).

## 5. Usar o Bearer na API aberta

```bash theme={null}
curl https://integracao.sandbox.cardapioweb.com/api/partner/v1/merchant \
  -H "Authorization: Bearer SEU_ACCESS_TOKEN"
```

O contexto do estabelecimento é resolvido automaticamente pela instalação vinculada ao token.

## 6. Renovar token

```bash theme={null}
curl -X POST https://integracao.sandbox.cardapioweb.com/api/partner/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=SEU_REFRESH_TOKEN" \
  -d "client_id=SEU_CLIENT_ID"
```

## 7. Revogar token

```bash theme={null}
curl -X POST https://integracao.sandbox.cardapioweb.com/api/partner/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=SEU_ACCESS_TOKEN_OU_REFRESH_TOKEN" \
  -d "client_id=SEU_CLIENT_ID"
```

A desinstalação do app pelo estabelecimento também revoga tokens ativos.

## Erros comuns

| Situação                                | Causa provável                                                              |
| --------------------------------------- | --------------------------------------------------------------------------- |
| `invalid_request` — `state is required` | Parâmetro `state` ausente no redirect para o portal                         |
| `access_denied` — somente Proprietário  | Usuário sem perfil Proprietário                                             |
| `invalid_client`                        | `client_id` inválido ou app não aprovado                                    |
| Redirect URI inválida                   | `redirect_uri` não corresponde ao cadastro no redirect ou na troca de token |
| PKCE inválido                           | `code_verifier` não corresponde ao `code_challenge`                         |
| HTTP 401 na API aberta                  | Token expirado, revogado ou instalação inativa                              |
| HTTP 403 — escopo insuficiente          | Token ou instalação sem o escopo exigido pelo endpoint                      |

<Warning>
  Não registre em logs valores de `access_token`, `refresh_token`, `code` ou
  `code_verifier`.
</Warning>

## Próximos passos

* [Referência da API — Obter token](/api-reference/autenticacao/oauth/obter-token)
* [Fluxos de integração](/fluxo-integracao)
* [Referência da API — Loja](/api-reference/loja/loja/consultar-loja)
