Plateforme de livraison de documents

Plateforme de livraison de documents.

Une plateforme multi-tenant pour l'envoi de documents, notifications et communications à grande échelle

Année.

2024

Employeur.

Sagacify

Rôle.

Développeur Full Stack

Contexte.

Une plateforme multi-tenant pour l'envoi de documents, notifications et communications à grande échelle : email, SMS, et intégrations avec des canaux tiers comme Doccle (courrier recommandé électronique) et DocuSign (signature électronique), construite comme un ensemble de microservices avec des workers adossés à AWS SQS. À chaque nouveau client entreprise, le modèle d'authentification devait supporter des tenants isolés, des permissions par tenant, et des intégrations serveur à serveur, sans que chaque nouveau tenant devienne un développement sur mesure.

Challenge.

Porter deux volets de la plateforme. D'abord, un système d'authentification et de permissions multi-tenant construit sur AWS Cognito : provisioning des tenants, cycle de vie complet des utilisateurs, un flux OAuth2 machine-to-machine pour les intégrations backend, et des permissions par rôle appliquées de façon identique sur le frontend et l'API, avec les vrais tokens d'accès gardés hors du navigateur. Ensuite, deux des intégrations de canaux de livraison de la plateforme, chacune suivant son propre protocole externe.

Décisions et compromis.

  • Rôles Intégrés au Token : Les rôles utilisateur sont intégrés directement dans le token Cognito à la connexion, via un trigger Lambda Pre Token Generation qui lit les rôles de chaque utilisateur par tenant en base et les injecte comme claim. L'API peut ainsi autoriser une requête à partir du token seul, sans aller-retour en base à chaque appel. Le backend reste la seule source de vérité pour ces rôles : le frontend se contente de refléter ce que l'API a déjà décidé, il ne calcule jamais les accès lui-même.

  • Déconnexion Immédiate au Changement : Cette rapidité a un coût, un changement de permission ne prend effet qu'au rafraîchissement du token. J'ai comblé cet écart en forçant une déconnexion immédiate dès qu'un accès change, plutôt que de laisser quelqu'un opérer avec des permissions obsolètes jusqu'à l'expiration naturelle du token.

  • Tokens Stockés Côté Serveur : Le navigateur ne détient jamais les vrais tokens Cognito : un identifiant de session opaque et de courte durée pointe vers les tokens réels, stockés côté serveur dans Redis. Un compromis assumé : plus de complexité côté backend, en échange de tokens qui ne peuvent ni être lus ni être rejoués depuis le client.

  • Identifiants OAuth2 par Tenant : Chaque tenant reçoit son propre id/secret OAuth2 rotatif pour les intégrations machine-to-machine via le grant client-credentials de Cognito, plutôt qu'une seule clé partagée entre toutes les intégrations.

  • Intégrations QR Code et SOAP/XML : Deux autres intégrations de canaux de livraison de la plateforme : un worker générant des liens de paiement avec QR code pour un canal, et l'intégration SOAP/XML derrière le canal Doccle. Les deux s'insèrent dans la même architecture de workers asynchrones que le reste de la plateforme, plutôt que d'être ajoutées à part.

Résultat.

La couche d'authentification et de permissions, ainsi que les deux intégrations de canaux de livraison, tournent en production, gérant chaque nouveau tenant entreprise qui rejoint la plateforme.

Stack.

Cognito pour l'identité, Redis pour les sessions, SQS pour tout ce qui est asynchrone.

TypeScript

React

Material UI

React Hook Form

Zod

Express.js

Objection.js

Unit Testing

AWS

Redis

Terraform