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

# Connecter une application (OAuth)

> Laissez un restaurant connecter votre application avec un bouton « Connecter EatNow » : OAuth 2, code d’autorisation avec PKCE.

Plutôt que de demander au restaurant de créer une clé API et de la coller dans
votre produit, votre application peut envoyer l’utilisateur sur EatNow, le
laisser choisir un restaurant et approuver les permissions, puis recevoir un
jeton. EatNow met en œuvre le flux OAuth 2 **code d’autorisation**
([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749)) avec **PKCE S256**
([RFC 7636](https://www.rfc-editor.org/rfc/rfc7636)), obligatoire.

Le jeton d’accès obtenu **est une clé de l’API partenaire** pour un restaurant :
il fonctionne avec toutes les routes de l’[API partenaire](/fr/api-reference/introduction)
permises par ses scopes, exactement comme une clé créée à la main. Il n’expire
pas et il n’y a pas de jeton de rafraîchissement ; il cesse de fonctionner
lorsqu’il est révoqué.

## Enregistrer votre application

Les applications sont enregistrées par EatNow. Envoyez-nous le nom de votre
application, son logo, les **URI de redirection** (comparées caractère par
caractère : schéma, hôte, port, chemin et paramètres) et les scopes nécessaires.
Vous recevez un `client_id` et un `client_secret`, affiché une seule fois :
gardez le secret sur votre serveur uniquement.

<Note>
  Une application éditée par EatNow (comme ClubNow) fonctionne sur tous les
  restaurants. Une application tierce exige en plus l’option API du restaurant,
  comme une clé créée à la main.
</Note>

## 1. Envoyer l’utilisateur sur la page de consentement

Générez un `code_verifier` (43 à 128 caractères parmi `A-Z a-z 0-9 - . _ ~`) et
un `state` aléatoire, gardez-les dans la session de l’utilisateur, puis
redirigez le navigateur vers :

```text theme={null}
https://app.eat-now.io/oauth/authorize
  ?client_id=VOTRE_CLIENT_ID
  &redirect_uri=https%3A%2F%2Fvotre-app.example%2Foauth%2Fcallback
  &response_type=code
  &scope=WEBHOOKS_WRITE%20RESERVATIONS_READ
  &state=STATE_ALEATOIRE
  &code_challenge=BASE64URL_SHA256_DU_VERIFIER
  &code_challenge_method=S256
```

| Paramètre | Requis | Valeur |
| - | - | - |
| `client_id` | Oui | L’identifiant de votre application. |
| `redirect_uri` | Oui | Une de vos URI de redirection enregistrées, à l’identique. |
| `response_type` | Oui | `code`. |
| `scope` | Oui | Noms de [scopes](/fr/api-reference/authentication#scopes) séparés par des espaces, parmi ceux autorisés. |
| `state` | Oui | Valeur opaque renvoyée telle quelle. Vérifiez-la au retour contre la falsification de requête. |
| `code_challenge` | Oui | `BASE64URL(SHA256(code_verifier))`, sans remplissage (43 caractères). |
| `code_challenge_method` | Oui | `S256`. `plain` est refusé. |
| `restaurant_hint` | Non | Id ou slug du restaurant à présélectionner, si l’utilisateur peut le connecter. |

```bash theme={null}
# Un verifier et son challenge
CODE_VERIFIER=$(openssl rand -base64 48 | tr '+/' '-_' | tr -d '=\n')
CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary \
  | openssl base64 | tr '+/' '-_' | tr -d '=\n')
```

L’utilisateur se connecte si besoin, voit votre application et les permissions
demandées, choisit un restaurant parmi ceux où il peut gérer les intégrations,
puis clique sur **Autoriser** ou **Refuser**.

## 2. Traiter le retour

EatNow redirige le navigateur vers votre `redirect_uri` avec `state` et soit un
`code`, soit une `error` :

| `error` | Signification |
| - | - |
| `access_denied` | L’utilisateur a cliqué sur **Refuser**. |
| `invalid_scope` | Un scope est inconnu ou non autorisé pour votre application. |
| `invalid_request` | `state` ou PKCE absent, méthode `plain`, ou paramètre répété. |
| `unsupported_response_type` | `response_type` n’est pas `code`. |

Un `client_id` inconnu ou désactivé, ou une `redirect_uri` non enregistrée,
n’est jamais redirigé : l’utilisateur voit l’erreur sur EatNow.

Le code est valable **5 minutes** et **une seule fois**.

## 3. Échanger le code contre un jeton

Depuis votre serveur, `POST https://app.eat-now.io/api/oauth/token` en
`application/x-www-form-urlencoded` (le JSON est aussi accepté). Authentifiez le
client par HTTP Basic (`client_id:client_secret`, chacun encodé comme un
formulaire) **ou** par `client_id` et `client_secret` dans le corps, pas les
deux.

```bash theme={null}
curl https://app.eat-now.io/api/oauth/token \
  -u "VOTRE_CLIENT_ID:VOTRE_CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code=LE_CODE \
  --data-urlencode redirect_uri=https://votre-app.example/oauth/callback \
  -d code_verifier="$CODE_VERIFIER"
```

```json theme={null}
{
  "access_token": "eat_partner_v1_3f2a…",
  "token_type": "Bearer",
  "scope": "RESERVATIONS_READ WEBHOOKS_WRITE",
  "restaurant": {
    "id": "cm1restaurant0000abcd",
    "name": "Le Bistrot",
    "slug": "le-bistrot"
  }
}
```

La réponse porte `Cache-Control: no-store`. Conservez le jeton côté serveur,
avec l’id du restaurant.

| HTTP | `error` | Cause |
| - | - | - |
| 400 | `invalid_request` | Paramètre absent ou répété, deux méthodes d’authentification du client, corps illisible. |
| 401 | `invalid_client` | Client inconnu ou désactivé, mauvais secret. |
| 400 | `invalid_grant` | Code inconnu, expiré ou déjà utilisé ; `redirect_uri` ou `code_verifier` qui ne correspond pas. |
| 400 | `unsupported_grant_type` | `grant_type` n’est pas `authorization_code`. |
| 429 | — | Limite de débit (60 requêtes par minute et par IP). Patientez avant de réessayer. |

<Warning>
  Un code présenté une seconde fois est refusé **et le jeton qu’il a émis est
  révoqué**. Ne rejouez jamais un échange qui a pu réussir : si la réponse s’est
  perdue, renvoyez l’utilisateur sur la page de consentement.
</Warning>

## 4. Appeler l’API partenaire

```bash theme={null}
curl https://app.eat-now.io/api/partner/v1/me \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Avec `WEBHOOKS_WRITE`, abonnez une URL HTTPS à des événements avec
`POST /api/partner/v1/webhook-endpoints`. Le secret de signature n’est renvoyé
que dans cette réponse. Chaque type d’événement demande le scope de lecture
correspondant, et les coordonnées ne figurent dans les charges utiles qu’avec
`RESERVATIONS_READ_SENSITIVE`. Voir
[Gérer les endpoints par l’API](/fr/api-reference/webhooks#gérer-les-endpoints-par-lapi).

## Cycle de vie d’une connexion

* **Reconnexion.** Une nouvelle autorisation pour le même restaurant ne
  révoque pas le jeton précédent : une fois la nouvelle connexion en place,
  révoquez l’ancien jeton avec `POST /api/oauth/revoke` (ci-dessous). Au plus
  3 jetons restent actifs par restaurant et par application : l’émission d’un
  quatrième révoque le plus ancien et supprime les endpoints de webhooks qu’il
  a créés.
* **Déconnexion par le restaurant.** Paramètres › Intégrations › Applications
  connectées liste les applications connectées ; **Déconnecter** révoque tous
  les jetons actifs de l’application sur ce restaurant et supprime leurs
  endpoints de webhooks. Vos appels reçoivent alors
  `401 INVALID_AUTHENTICATION` : proposez à l’utilisateur de se reconnecter.
* **Déconnexion par votre application.** `POST /api/oauth/revoke`
  ([RFC 7009](https://www.rfc-editor.org/rfc/rfc7009)) avec `token` et la même
  authentification du client que pour l’échange. La réponse est `200`, même pour
  un jeton inconnu ou déjà révoqué.

```bash theme={null}
curl https://app.eat-now.io/api/oauth/revoke \
  -u "VOTRE_CLIENT_ID:VOTRE_CLIENT_SECRET" \
  -d token="$ACCESS_TOKEN"
```
