diff --git a/IA_agents/idnot-front-agnostic.md b/IA_agents/idnot-front-agnostic.md new file mode 100644 index 0000000..3518940 --- /dev/null +++ b/IA_agents/idnot-front-agnostic.md @@ -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 d’ensemble +- 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 d’environnement – Backend (dev3) +Ajouter dans l’environnement du back: +```bash +BACK_HMAC_SECRET= +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` 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 d’environnement – 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 l’URL 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 d’open 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=&state=` → 302 vers `next_url#authToken=...` +- Front: bouton IdNot → parcours complet → session active + +### Points d’attention +- 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 + +