docs(idnot): document front-agnostic IdNot flow (front/back/nginx/env/tests)

This commit is contained in:
LeCoffre Deployment 2025-09-23 06:59:45 +00:00
parent 0b2edeb94c
commit e9d8f826d9

View File

@ -0,0 +1,126 @@
### IdNot Flux agnostique du front (dev3 backend, dev4 frontend)
Objectif: permettre à n'importe quel front (domaine inconnu, y compris localhost) d'utiliser l'auth IdNot sans modifier le redirect_uri déclaré chez IdNot.
### Vue densemble
- Le redirect_uri IdNot reste: `http://local.4nkweb.com:3000/authorized-client`.
- Nginx sur dev3 intercepte ce host/port et redirige vers `https://dev3.4nkweb.com/idnot/callback` en conservant la query (`code`, `state`).
- Le front demande au back un `state` signé contenant `next_url` (URL finale dynamique du front).
- Le back valide `state`, échange le `code` chez IdNot, crée la session, puis 302 vers `next_url#authToken=<...>`.
### Composants
- Backend (dev3, lecoffre-back-mini)
- Frontend (dev4, lecoffre-front)
- Nginx dev3: capte `local.4nkweb.com:3000/authorized-client``/idnot/callback` et proxy /api
- Nginx dev4: sert `/lecoffre/` et proxifie `/api/` vers dev3 (inchangé pour ce flux)
### Variables denvironnement Backend (dev3)
Ajouter dans lenvironnement du back:
```bash
BACK_HMAC_SECRET=<random-long-hex>
STATE_TTL_SECONDS=180
ALLOW_LOCALHOST_REDIRECTS=true
ALLOWED_REDIRECT_HOST_PATTERNS=^dev4\.4nkweb\.com$,^localhost$,^127\.0\.0\.1$
```
### Implémentation Backend (dev3)
- Service de state `src/services/state.service.ts`
- `signState(nextUrl: string)``{state}`
- `verifyState(state: string)``{ next_url, nonce, ts }`
- payload: `{ next_url, nonce, ts }` JSON
- signature: `HMAC-SHA256(payload, BACK_HMAC_SECRET)`
- TTL: `now - ts <= STATE_TTL_SECONDS`
- Anti-rejeu: `Map<nonce, expiry>` nettoyée périodiquement
- Validation `next_url`: URL absolue; schéma https, ou http autorisé seulement si `ALLOW_LOCALHOST_REDIRECTS=true` et host ∈ {`localhost`, `127.0.0.1`}; host match `ALLOWED_REDIRECT_HOST_PATTERNS`
- Handlers
- `POST /api/v1/idnot/state` (body: `{ next_url }`) → 200 `{ state }`
- `GET /idnot/callback` (query: `code`, `state`)
- `verifyState(state)` → récupère `next_url`
- `IdNotService.exchangeCodeForTokens(code)` (existant)
- Crée la session/authToken
- `302` vers `next_url#authToken=<...>` (fragment recommandé)
- Erreurs: 400 (state invalide), 502 (échec IdNot), 400 (next_url invalide)
- Routes à monter
```ts
router.post('/api/v1/idnot/state', StateHandlers.createState)
router.get('/idnot/callback', IdNotCallbackHandlers.callback)
```
### Nginx dev3
- Vhost capteur du redirect IdNot (ex: `/etc/nginx/sites-available/local.4nkweb.com-3000`)
Avant:
```nginx
return 301 https://dev4.4nkweb.com/lecoffre$request_uri;
```
Après:
```nginx
return 301 https://dev3.4nkweb.com/idnot/callback$request_uri;
```
- Vhost principal dev3 (ex: `/etc/nginx/sites-available/dev3.4nkweb.com`)
```nginx
location ^~ /api/ { proxy_pass http://127.0.0.1:8080; include /etc/nginx/proxy_params; }
location = /idnot/callback { proxy_pass http://127.0.0.1:8080; include /etc/nginx/proxy_params; }
```
### Variables denvironnement Front (dev4)
Ajouter au build/environnement front:
```bash
NEXT_PUBLIC_IDNOT_REDIRECT_URI_FIXED=http://local.4nkweb.com:3000/authorized-client
NEXT_PUBLIC_BACK_BASE=https://dev3.4nkweb.com
# Rappel API front (déjà en place)
NEXT_PUBLIC_BACK_API_PROTOCOL=https
NEXT_PUBLIC_BACK_API_HOST=dev4.4nkweb.com
NEXT_PUBLIC_BACK_API_PORT=443
NEXT_PUBLIC_BACK_API_ROOT_URL=/api
NEXT_PUBLIC_BACK_API_VERSION=v1
```
### Implémentation Front (dev4)
- Exposition des variables (next.config.js)
- `NEXT_PUBLIC_IDNOT_REDIRECT_URI_FIXED`, `NEXT_PUBLIC_BACK_BASE`
- VariablesFront.ts
- Ajouter `IDNOT_REDIRECT_URI_FIXED?: string;`
- Ajouter `BACK_BASE?: string;`
- Démarrage IdNot (ex: `StepEmail/index.tsx`)
1) `POST ${BACK_BASE}/api/v1/idnot/state` avec `{ next_url: window.location.origin + '/authorized-client' }`
2) Récupérer `{ state }`
3) Construire lURL IdNot avec:
- `redirect_uri=${NEXT_PUBLIC_IDNOT_REDIRECT_URI_FIXED}`
- `state=${state}`
- `client_id`, `scope`, `response_type=code`
- Retour (page `authorized-client`)
- Lire `#authToken` dans le fragment
- Stocker cookie `leCoffreAccessToken`
- Nettoyer le hash
### Sécurité
- Pas dopen redirect: HMAC + TTL + nonce + whitelist host
- `#authToken` dans le fragment pour éviter logs/proxys
- Rate-limit sur `POST /api/v1/idnot/state`
- Logs: ne pas exposer `next_url` complet
### Séquence (texte)
1) Front → Back: POST `/api/v1/idnot/state` body `{ next_url }`
2) Back → Front: `{ state }`
3) Front → IdNot: `/authorize?client_id=...&redirect_uri=http://local.4nkweb.com:3000/authorized-client&state=...`
4) IdNot → dev3 Nginx: `http://local.4nkweb.com:3000/authorized-client?code&state`
5) Nginx dev3 → Back: `GET /idnot/callback?code&state`
6) Back → IdNot: échange de token; session
7) Back → Front: `302 next_url#authToken=...`
8) Front: stocke token, poursuit navigation
### Tests
- `POST https://dev3.4nkweb.com/api/v1/idnot/state` → 200, `{ state }`
- `GET https://dev3.4nkweb.com/idnot/callback?code=<réel>&state=<state>` → 302 vers `next_url#authToken=...`
- Front: bouton IdNot → parcours complet → session active
### Points dattention
- Ajouter les domaines requis dans `ALLOWED_REDIRECT_HOST_PATTERNS`
- TTL court (180s) et purge des nonces
- En prod, préférer cookies sécurisés et durées minimales