Auth et logique de session
Ce chapitre a pour objectif de vous expliquer, d'une part comment fonctionne la logique de session et l'initialisation d'un nouveau projet sur votre OAV lors du décrochage et d'autre part l'authentification du client (de l'application React) au server.

Session utilisateur
à chaque nouvelle connexion du client, le serveur crée une nouvelle session et génÚre un cookie. Les sessions et leurs informations sont sauvegardées dans la collection sessions de la base de données MongoDB.
Les variables d'environnement suivantes sont liées au cookie de session :
- SESSION_COOKIE_MAX_AGE le temps en minutes avant expiration du cookie et de la session utilisateur, 60 minutes par défaut.
- SESSION_SECRET la chaßne de caractÚres utilisée pour signer l'id de la session liée au cookie.
Souvenez vous qu'une session utilisateur peut ĂȘtre liĂ©e Ă plusieurs projets client.
Générer un token de session
Pour générer un token de session, assurez-vous que le service fasst-sessions (ou un service équivalent) est lancé et accessible depuis la stack de votre projet.
Un token de session gĂ©nĂ©rĂ© ne peut ĂȘtre « consommĂ© » qu'une seule fois par votre OAV.
Exemple avec fasst-sessions en local :
curl --request POST \
--url http://localhost:3005/api/sessions/tokens \
--header 'Content-Type: application/json' \
--data '{
"applicant": "magic",
"metadata": {
"externalId": "project-AAA"
}
}'Lors de l'appel Ă votre service de sessions, assurez-vous de renseigner la bonne URL et les bons paramĂštres en fonction de votre environnement.
Le champ metadata du body de la requĂȘte correspond au context client du projet. Vous pouvez renseigner par exemple l'identifiant client du projet, champ metadata.externalId ou toutes autres informations utiles qui vous seront nĂ©cessaires lors de la crĂ©ation et l'initialisation de l'entitĂ© Project.
Vous obtiendrez alors en réponse un objet JSON contenant votre token de session :
{ "token": "my-generated-token" }Callback d'initialisation du projet
CÎté serveur, le fichier server/controllers/project/project.mjs expose la callback d'initialisation du projet initProjectFromContext qui vous permet de créer et d'initialiser l'entité Project selon les besoins et les spécificités de votre OAV et du contexte client.
La callback initProjectFromContext est passée en paramÚtre à la méthode startServer importée depuis la dépendance @fasstech/oip-starter-utils. La méthode startServer est appelée dans le fichier server/index.mjs de votre OAV et initialise le server.
La callback initProjectFromContext reçoit en paramÚtre l'objet context qui correspond au contexte client du projet lié au token généré.
Depuis la version v3.4.1 de la dépendance @fasstech/oip-starter-utils, la callback d'initialisation du projet reçoit en second paramÚtre sessionId qui correspond à l'identifiant de la session utilisateur actuelle.
Exemple :
import { Entities } from '@fasstech/oip-core';
export const initProjectFromContext = async (context, sessionId) => {
// retrieve info from context client
const { externalId } = context;
// try to get an existing Project entity
let project = await Entities('Project').get({ externalId });
// if the project exists, we must return it
if (project) {
return project;
}
// else we create a new one and init it
project = await Entities('Project').create({ externalId });
project = await Entities('Project').save(project);
// and return it
return project;
};Décrocher sur l'OAV
Deux types de décrochage sur l'OAV sont possibles. Décrocher avec un token ou avec l'identifiant interne d'un projet.
Ainsi, lors du décrochage sur l'OAV via son URL, un de ces deux paramÚtres (query string parameters) est attendu :
- token dont la valeur attendue correspond à un token fraßchement généré par votre service de sessions
- projectId dont la valeur attendue correspond Ă l'identifiant d'un projet (id de l'entitĂ© Project) prĂ©cĂ©demment initialisĂ© lors de la mĂȘme session utilisateur
Décrocher avec un token
Si le paramÚtre d'URL token est trouvé lors du décrochage, le code client fait un appel HTTP au server pour initlialiser l'entité Project à partir du token et ainsi lier le projet à la session utilisateur en cours :
GET /session?token=my-generated-tokenLe server essaie alors de rĂ©cupĂ©rer le context client liĂ© au token par un appel HTTP au service de sessions (le mĂȘme service qui a gĂ©nĂ©rĂ© le token) :
GET ${SESSIONS_SERVICE_URL}/api/sessions/tokens?token=${token}&sessionId=nullSi l'appel réussi un objet qui représente le context client du projet est reçu en réponse :
{ "externalId": "project-AAA" }Une fois le context du projet récupéré, la callback d'initialisation du projet est appellée avec context passé en paramÚtre et l'entité Project est initialisée ou récupérée et liée à la session utilisateur en cours.
Enfin, en réponse à l'appel initial GET /session du client, le server renvoie projectId qui correspond à l'identifiant de l'entité Project résolue.
Si une erreur survient lors du processus, une erreur 401 est renvoyée au client.
Décrocher avec l'identifiant d'un projet
Si le paramÚtre d'URL projectId est trouvé lors du décrochage, le code client fait un appel HTTP au server pour essayer de récupérer l'entité Project existante :
GET /session?projectId=xxxxx*Si l'entitĂ© *Project relative existe, elle doit ĂȘtre impĂ©rativement liĂ©e Ă la session utilisateur en cours. En cas d'erreur, une erreur 401 est renvoyĂ©e au client.
Si l'appel réussi, le server renvoie projectId qui correspond à l'identifiant de l'entité Project résolue et vous reprendrez alors le parcours sur la derniÚre vue active du projet concerné.
Identifiant du projet résolu
Une fois que le server a résolu l'entité Project lors du décrochage, l'identifiant relatif projectId est renvoyé au client en réponse à l'appel GET /session
projectId sera alors renseignĂ© lors de chaque appel graphQL du client au server dans les headers de la requĂȘte. Nom du header : fasst-oav-project-id
C'est grùce à cet header que le server résout lors des appels graphQL l'objet process contenu dans le context graphQL qui vous servira à récupérer projectId dans les resolvers et dans les composants de vos vues (se référer à ce chapitre pour plus de détails)
Pour des raisons de sécurité, lors de chaque appel graphQL, le server vérifie que le projet identifié par le header fasst-oav-project-id fait bien partie de la liste des projets liés à la session utilisateur actuelle.
Reprise d'un projet existant
Si vous souhaitez reprendre le parcours d'un projet initié par une autre session utilisateur ou lors d'une session expirée, alors il vous faut re-générer un token auprÚs du service de sessions.
Vous devez vous assurer de renseigner dans le body de la requĂȘte (champ metadata), quelque chose qui fait rĂ©fĂ©rence au context client initial et qui vous aidera Ă identifier l'entitĂ© Project existante correspondante dans la callback d'initialisation du projet. Par exemple en renseignant l'externalId du projet concernĂ©.
Une fois le token obtenu, vous pouvez décrocher sur l'OAV avec le token renseigné en paramÚtre dans l'URL.
Exemple : http://localhost:8000/?token=my-generated-token
Vous reprendrez alors le parcours sur la derniÚre vue active du projet concerné.
Désactiver la vérification du token
â ïž La vĂ©rification du token de session ne doit jamais ĂȘtre dĂ©sactivĂ©e en mode production â ïž
Lors de vos phases de développement en local, pour vous éviter à devoir générer des tokens auprÚs du service de sessions de maniÚre redondante, vous pouvez désactiver la vérification du token lors du chargement de l'application web en passant à true la valeur de la variable d'env SESSION_CHECKING_DISABLED
Lorsque la vérification du token est désactivée, le server utilise le mock du context client (définit dans le fichier server/mocks/context.mjs) lors du décrochage. Par conséquent vous n'avez pas besoin de renseigner le paramÚtre token dans l'URL. Par ailleurs, si le paramÚtre token est présent dans l'URL, il sera ignoré.
Logique d'initialisation du projet lorsque la vérification du token est désactivée :
- si le paramÚtre projectId est trouvé dans l'URL, le server essaiera de récupérer le projet relatif :
- si le projet est trouvé, il sera lié à la session utilisateur en cours s'il n'est pas encore lié à cette derniÚre et projectId est renvoyé au client
- sinon une erreur 401 est renvoyée au client
- sinon, le server appelle la callback d'initialisation du projet en passant en paramÚtre le mock du context client. Vous pouvez éditer le mock du context selon vos besoins, fichier server/mocks/context.mjs. Une fois l'entité Project résolue par la callback d'initialisation du projet, elle sera liée à la session utilisateur en cours si elle n'est pas encore liée à cette derniÚre et projectId est renvoyé au client
Authentification du client
Ce chapitre Ă pour but d'expliquer la logique d'authentifaction du client au server.
L'endpoint /graphql du server est sĂ©curisĂ© par dĂ©faut. Le server vĂ©rifie le Bearer token dĂ©finit dans les headers de chaque requĂȘte entrante.
Dans ce chapitre, le terme « client » fait référence à l'application React de votre OAV.
La logique d'authentification du client se fait en parallÚle et de maniÚre indépendante à la logique de session expliquée précédemment. Ce sont deux logiques distinctes, qui sécurisent votre OAV.
Les variables d'environnement relatives Ă l'authentification du client :
API_USER_ID=fasst-oav-oip
API_KEY=00000000-0000-0000-0000-000000000000
API_KEYS=fasst-oav-oip:00000000-0000-0000-0000-000000000000
JWT_SECRET=33333333-3333-3333-3333333333Explications :
Lors du chargement de l'application React dans le navigateur web, le client échange les valeurs des variables d'env API_USER_ID et API_KEY contre des tokens via l'endpoint /u/token du server.
Le server vĂ©rifie les credentials du client reçus grĂące Ă la variable d'env API_KEYS (dont sa valeur doit ĂȘtre une concatĂ©nation des valeurs de API_USER_ID et de API_KEY). Si les credentials sont valides alors le server gĂ©nĂšre et renvoie au client un access token et un refresh token. Ces tokens sont signĂ©s par le server en utilisant la valeur de la variable d'env JWT_SECRET
Lors de ses appels graphQL, le client utilisera alors l'access token reçu par le server en tant que Bearer token pour s'authentifier auprÚs du server.
Dans le cas d'une erreur 401 retournée par le server lors d'un appel graphQL, le client essaie de rafraßchir l'access token via l'endpoint /u/token du server en passant le refresh token gardé en mémoire et relance l'opération graphQL qui a échouée. Par défaut, l'expiration de l'access token est définie sur 24 heures.
Garanties de sécurité
Résumé des garanties de sécurité en production :
- il n'est pas possible de décrocher sur l'OAV sans token de session
- si l'utilisateur souhaite reprendre un projet existant, il doit générer un token de session faisant référence au projet souhaité et re-décrocher sur l'OAV
- si l'utilisateur entre manuellement projectId dans l'URL, projectId doit faire rĂ©fĂ©rence Ă un projet prĂ©cĂ©damment initialisĂ© lors de la mĂȘme session utilisateur
- plusieurs projets peuvent ĂȘtre liĂ©s Ă une mĂȘme session utilisateur
- un projet peut ĂȘtre liĂ© Ă plusieurs sessions utilisateur
- l'application React (le client) s'authentifie auprĂšs du server (OAuth 2.0)
- l'endpoint /graphql du server est protégé, le server vérifie :
- le Bearer token pour authentifier et autoriser le client
- que le projet identifié par le header fasst-oav-project-id est bien lié à la session utilisateur
Configurer les attributs du cookie de session
La configuration des attributs du cookie de session est disponible à partir de la version 3.4.0 de la dépendance OIP Starter Utils.
Le server utilise la dépendance npm express-session pour la gestion du cookie de session.
La configuration par défaut du cookie est la suivante :
{
sameSite: 'lax',
maxAge: process.env.SESSION_COOKIE_MAX_AGE,
secure: true // en mode production
}Si vous souhaitez modifier la configuration par défaut, vous pouvez passer un objet cookieOptions en paramÚtre de la méthode startServer appelée par défaut dans le fichier server/index.mjs
Exemple :
import { start as startServer } from '@fasstech/oip-starter-utils/server';
const config = {
// ...
cookieOptions: {
secure: process.env.NODE_ENV === 'production',
httpOnly: process.env.NODE_ENV === 'production',
sameSite: process.env.NODE_ENV === 'production' ? 'none' : false
}
};
const { app } = await startServer(config);Points Ă savoir :
- l'option secure sera toujours activée en mode production pour des raisons de sécurité
- l'option maxAge sera toujours définie sur la valeur de la variable d'environnement SESSION_COOKIE_MAX_AGE si elle existe ou 60 minutes par défaut
Pour la liste complÚte et le détail des options de configuration acceptÚes, veuillez vous référer à la documentation des options liées au cookie de la dépendance npm express-session