Sticky Notes est une appli fullstack de prise de notes développée dans le cadre du Master Ynov M2. Spring Boot 4 côté API, Angular 21 côté SPA & H2.
Un utilisateur tape ses identifiants. Le serveur lui répond avec un JWT qu'il a lui-même signé, avec une clé RSA générée il y a quelques minutes au démarrage de la JVM. Pas de Keycloak, pas d'Auth0, pas de service d'authentification séparé. Le backend joue les deux rôles : il émet le token, il le valide.
Sticky Notes est une appli fullstack de prise de notes développée dans le cadre du Master Ynov M2. Spring Boot 4 côté API, Angular 21 côté SPA, H2 en mémoire derrière. L'intérêt du projet ne tient pas aux notes elles-mêmes mais à la chaîne d'authentification qu'on construit autour.
Pas de Docker, pas de proxy, pas de reverse-proxy Nginx. Un seul start.sh qui tue ce qui traîne sur les ports 9090 et 4200, lance Maven en background, attend dix secondes que la JVM chauffe, puis lance Angular. C'est rustique, et c'est précisément le bon niveau de complexité pour un projet académique.
Le flux d'authentification tient en cinq étapes. Le client envoie ses identifiants en HTTP Basic vers POST /token. Spring Security authentifie via UserDetailsService contre la base H2. Le TokenService génère un JWT RS256 signé avec une paire RSA 2048 bits, l'issuer est "self", la durée est d'une heure. Le client stocke le token et le renvoie en Bearer pour toutes les requêtes suivantes. Le Resource Server valide la signature à chaque appel avec la clé publique gardée en mémoire.
Le détail qui fait toute la différence avec une vraie infra : les clés RSA sont régénérées à chaque redémarrage de la JVM. Tous les tokens émis avant le restart deviennent invalides. C'est acceptable pour un projet démo, ça ne tient pas une seconde en production où il faudrait persister la paire de clés (vault, fichier monté, secret Kubernetes selon le contexte).
Côté frontend, deux choix idiomatiques d'Angular moderne méritent d'être soulignés.
Premier choix, l'auth state passe par un Signal, pas un BehaviorSubject RxJS. AuthService.isAuthenticated est un Signal lu directement par les guards et les composants, qui se met à jour automatiquement quand le token apparaît ou disparaît du localStorage. Plus simple à lire, moins de boilerplate d'abonnement.
Deuxième choix, l'intercepteur HTTP est fonctionnel (HttpInterceptorFn), pas une classe. Une fonction pure qui clone la requête sortante, injecte le header Authorization: Bearer si un token existe, et passe au handler suivant. La nouvelle API recommandée depuis Angular 15, plus testable et plus lisible que l'ancienne classe HttpInterceptor.
Deux points.
Le pattern self-issued JWT est élégant tant qu'on assume ses limites. Pas de refresh token, pas de révocation, pas de persistance des clés, ce sont trois manques qu'il faut comprendre avant de le copier-coller dans un vrai projet. Le code Spring Security est court et lisible, ce qui rend la tentation forte.
Cypress avec cy.intercept change le rapport aux tests E2E. Le backend n'a pas besoin de tourner, les réponses sont mockées requête par requête, les tests deviennent rapides et déterministes. La contrepartie classique reste vraie : on teste l'UI, pas l'intégration réelle avec l'API.