# Brancher son fournisseur d'identité

> Objectif : exiger un jeton là où le contrat l'exige, sans écrire de code.

Guide - Depuis la version 0.3.0 - Flexway v1.6.3 - https://flexway.io/docs/operations-identity/

> Guide d'exploitation : configurer, déployer et observer la passerelle. Ce que fait la capacité côté produit : [guide produit](https://flexway.io/docs/product-overview/) ; l'appeler : [guide développeur](https://flexway.io/docs/developer-overview/).

**Objectif** : exiger un jeton là où le contrat l'exige, sans écrire de code.

**Commande** - la configuration dit **comment vérifier** une identité :

```yaml
auth:
  tenant_header: X-Tenant              # où le tenant est écrit vers l'amont
  issuers:
    - name: staff
      discovery: https://id.example.com/realms/staff/.well-known/openid-configuration
      audience: api
      roles_claim: realm_access.roles  # Keycloak ; `roles` pour Entra ID
    - name: customers
      discovery: https://login.example.net/.well-known/openid-configuration
      audience: api
      tenant_claim: org
```

Le **contrat** dit **ce qui est exigé**, opération par opération - jamais la configuration :

```yaml
components:
  securitySchemes:
    customers: { type: openIdConnect, openIdConnectUrl: https://login.example.net/.well-known/openid-configuration }
    staff: { type: http, scheme: bearer }
paths:
  /me/orders:
    get:
      operationId: listMyOrders
      security: [ { customers: [orders:read] } ]   # une portée
  /admin/report:
    get:
      operationId: getAdminReport
      security: [ { staff: [admin] } ]             # un rôle (schéma http bearer)
```

Le nom d'un schéma ne **choisit pas** l'émetteur : un jeton de **n'importe quel** émetteur déclaré
satisfait l'opération s'il porte les portées ou les rôles exigés. Nommez les schémas comme vos
émetteurs pour le lecteur ; la confiance se décide dans `auth.issuers`, l'accès par les portées et
les rôles.

**Vérif** :

| Appel | Réponse |
| --- | --- |
| Sans jeton | `401`, `WWW-Authenticate: Bearer` |
| Jeton invalide, expiré, du mauvais émetteur ou de la mauvaise audience | `401`, `error="invalid_token"` - jamais `500`, et jamais le motif exact |
| Jeton valide sans la portée ou le rôle | `403`, `error="insufficient_scope", scope="..."` - les portées exigées ; vide quand seul un rôle manque, un rôle n'étant pas une portée OAuth |
| Jeton valide avec ce qu'il faut | relayé ; l'amont reçoit `Authorization` et `X-Tenant` tiré de la claim |

> **Horizon partagé** (`0.1.0`) : un fournisseur joint sous un nom interne et qui annonce son nom
> public - Keycloak avec `KC_HOSTNAME` public et des URL internes dynamiques - se déclare avec
> `issuer` à côté de `discovery`. La découverte et chaque jeton doivent énoncer exactement cet
> `issuer` ; la pile locale l'utilise (`config/dev/flexway.yaml`).
>
> ```yaml
>     - name: staff
>       discovery: http://keycloak:8080/realms/staff/.well-known/openid-configuration   # joint
>       issuer: https://login.example.com/realms/staff                                   # énoncé
> ```
>
> **Plusieurs audiences** (`1.0.0`) : pendant le renommage d'une audience, `audiences` accepte un
> jeton émis pour **l'une** d'elles - l'ancien nom et le nouveau, le temps que les jetons de
> l'ancien expirent. Exclusif de `audience` ; `/config` liste les audiences acceptées.
>
> ```yaml
>     - name: customers
>       discovery: https://login.example.net/.well-known/openid-configuration
>       audiences: [orders-api, api]
> ```
>
> Plusieurs émetteurs cohabitent, de fournisseurs différents : déclarez-en autant que nécessaire.
> Un client a souvent un fournisseur pour ses employés et un autre pour ses clients finaux. Le
> démarrage n'attend aucun fournisseur : tant que ses clés ne sont pas chargées, ses jetons
> reçoivent `401`, et le journal le dit (`issuer not reachable yet`).
>
> **Fermé par défaut** : un en-tête que le contrat ne déclare pas n'atteint pas l'amont, un
> paramètre de requête non déclaré est refusé (`400`, en le nommant), une origine de navigateur non
> autorisée est refusée (`403`). Pour l'autoriser, une politique `cors` :

```yaml
policies:
  definitions:
    browser: { type: cors, config: { allow_origins: ["https://app.example.com"], allow_credentials: true } }
  chains:
    global: [browser]
```
