---
title: "Autenticação — BeeFood API"
description: "Integração direta (Client Credentials) e Conectar com BeeFood (Authorization Code + PKCE)."
url: "https://developer.beefood.com.br/docs/oauth/usar-token"
group: "OAuth"
lang: "pt"
---
# Autenticação — API BeeFood

As duas opções são OAuth 2.0 e geram tokens para as mesmas rotas /v1, escopos e header Authorization: Bearer. O que muda é como o token é obtido.

| | Integração direta | Conectar com BeeFood |
| --- | --- | --- |
| Fluxo | Client Credentials | Authorization Code + PKCE |
| Credencial | Lojista cria no portal Developers | Lojista conecta no site da integradora |
| Integradora recebe | clientId + clientSecret | Tokens sem ver segredo |
| Indicado para | Sistema próprio ou poucos clientes | Muitos lojistas |
| Cadastro prévio | Não | Não |

## Ambientes
- Produção: https://api.beefood.app
- Sandbox: https://api-sandbox.beefood.app
- Descoberta OAuth: GET /.well-known/oauth-authorization-server
- Autorização (login + consentimento): produção https://beefood.app/oauth/authorize; sandbox https://api-sandbox.beefood.app/oauth/authorize
- Token: POST /v1/oauth/token
- Revogação: POST /v1/oauth/revoke

## Guia 1 — Integração direta (Client Credentials)
O lojista cria uma credencial no portal Developers, escolhe os escopos e entrega clientId e clientSecret. O segredo aparece uma única vez e deve ficar apenas no servidor.


a) Gerar token:

```bash
curl -X POST 'https://api.beefood.app/v1/oauth/token' -H 'Content-Type: application/json' -d '{"grantType":"client_credentials","clientId":"<CLIENT_ID>","clientSecret":"<CLIENT_SECRET>"}'
```
```javascript
const response = await fetch("https://api.beefood.app/v1/oauth/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ grantType: "client_credentials", clientId: "<CLIENT_ID>", clientSecret: "<CLIENT_SECRET>" }) });
const tokens = await response.json();
```
Resposta 200: `{ "accessToken": "<ACCESS_TOKEN>", "refreshToken": "<REFRESH_TOKEN>", "expiresAt": "<ISO_8601>" }`.

b) Renovar (refresh rotaciona imediatamente o par anterior):
```bash
curl -X POST 'https://api.beefood.app/v1/oauth/token' -H 'Content-Type: application/json' -d '{"grantType":"refresh_token","clientId":"<CLIENT_ID>","refreshToken":"<REFRESH_TOKEN>"}'
```
```javascript
await fetch("https://api.beefood.app/v1/oauth/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ grantType: "refresh_token", clientId: "<CLIENT_ID>", refreshToken: "<REFRESH_TOKEN>" }) });
```

c) Revogar (200 sem corpo):
```bash
curl -X POST 'https://api.beefood.app/v1/oauth/revoke' -H 'Content-Type: application/json' -d '{"clientId":"<CLIENT_ID>","clientSecret":"<CLIENT_SECRET>","token":"<TOKEN>"}'
```
```javascript
await fetch("https://api.beefood.app/v1/oauth/revoke", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId: "<CLIENT_ID>", clientSecret: "<CLIENT_SECRET>", token: "<TOKEN>" }) });
```

## Guia 2 — Conectar com BeeFood (Authorization Code + PKCE)
Não existe cadastro prévio: a integradora escolhe o client_id (o nome do aplicativo, visto pelo lojista) e o redirect_uri. Não há client_secret; use os mesmos valores em todo o fluxo.

1. Backend gera code_verifier (43–128 caracteres), code_challenge = BASE64URL(SHA256(code_verifier)) sem padding e state novo a cada clique; guarda verifier e state na sessão.
```javascript
import { randomBytes, createHash } from "node:crypto";
const codeVerifier = randomBytes(32).toString("base64url");
const codeChallenge = createHash("sha256").update(codeVerifier).digest("base64url");
const state = randomBytes(16).toString("base64url");
```
2. Redireciona o navegador a `https://beefood.app/oauth/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI_URL_ENCODED>&code_challenge=<CODE_CHALLENGE>&code_challenge_method=S256&state=<STATE>`. Só a conta principal pode autorizar; o lojista escolhe escopos no consentimento (não enviar scope na URL).
3. BeeFood devolve `code`, `state` e `iss` ao callback. Se recusado, `error=access_denied`. Conferir state com a sessão; descartar divergências. Client ID/redirect URI inválidos não redirecionam.
4. O backend troca o code (10 minutos, uso único) com code_verifier:
```bash
curl -X POST 'https://api.beefood.app/v1/oauth/token' -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=authorization_code' --data-urlencode 'client_id=<CLIENT_ID>' --data-urlencode 'code=<CODE>' --data-urlencode 'redirect_uri=<REDIRECT_URI>' --data-urlencode 'code_verifier=<CODE_VERIFIER>'
```
```javascript
const body = new URLSearchParams({ grant_type: "authorization_code", client_id: "<CLIENT_ID>", code: "<CODE>", redirect_uri: "<REDIRECT_URI>", code_verifier: codeVerifier });
const response = await fetch("https://api.beefood.app/v1/oauth/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body });
const tokens = await response.json();
```
Resposta 200: `{ "access_token": "<ACCESS_TOKEN>", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "<REFRESH_TOKEN>" }`.
5. GET /v1/store/merchants com Authorization: Bearer <ACCESS_TOKEN> identifica os restaurantes autorizados.

Renovar:
```bash
curl -X POST 'https://api.beefood.app/v1/oauth/token' -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'grant_type=refresh_token' --data-urlencode 'client_id=<CLIENT_ID>' --data-urlencode 'refresh_token=<REFRESH_TOKEN>'
```
```javascript
await fetch("https://api.beefood.app/v1/oauth/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "refresh_token", client_id: "<CLIENT_ID>", refresh_token: "<REFRESH_TOKEN>" }) });
```
Desconectar (200 sem corpo, mesmo se token já inválido):
```bash
curl -X POST 'https://api.beefood.app/v1/oauth/revoke' -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=<CLIENT_ID>' --data-urlencode 'token=<TOKEN>'
```
```javascript
await fetch("https://api.beefood.app/v1/oauth/revoke", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ client_id: "<CLIENT_ID>", token: "<TOKEN>" }) });
```

## Uso, escopos e erros
Use `Authorization: Bearer <ACCESS_TOKEN>` em /v1. Access token dura 1 hora, refresh token 30 dias. Renove antes de expirar ou após 401; salve o par novo de forma atômica, uma renovação por restaurante. Se falhar com 401, reconecte. Escrita inclui leitura do mesmo recurso. Veja https://developer.beefood.com.br/docs/scopes. Ausência do escopo retorna 403.

Erro padrão: `{ "message": "Invalid client credentials", "status": 401 }`. 400: campo obrigatório ou grant_type inválido; 401: credencial, code, verifier, refresh ou token inválido/expirado; 403: escopo insuficiente.

Segurança: PKCE e state novos no backend a cada clique; conferir state; trocar code no backend; criptografar tokens por restaurante; salvar refresh rotacionado atomicamente; nunca repetir escritas POST/PUT/PATCH/DELETE após timeout; oferecer Desconectar chamando /v1/oauth/revoke.

Página: https://developer.beefood.com.br/docs/oauth/usar-token
