Implémentation de l'authentification avec Better-Auth
Introduction : de la conception à l’implémentation
L’implémentation du système d’authentification de DropIt constitue pour moi une étape cruciale où les choix architecturaux présentés dans la conception sécurisée se concrétisent en code fonctionnel. Cette phase m’a permis de découvrir la complexité pratique de la mise en œuvre d’un système d’authentification robuste, au-delà des concepts théoriques étudiés en formation.
Le choix de Better-Auth, motivé par son approche hybride combinant JWT et sessions révocables, m’a confronté à l’apprentissage d’une technologie récente et moins documentée que les solutions classiques. Cette exploration m’a enrichi techniquement tout en me faisant comprendre les enjeux réels de l’intégration d’outils tiers dans un projet professionnel.
Cette implémentation s’articule autour de plusieurs composants interdépendants que j’ai dû comprendre et maîtriser progressivement : la configuration du service d’authentification, la gestion des entités de données, la protection des routes via des guards, et l’exposition d’une API cohérente pour les applications clientes.
Vue d’ensemble de l’architecture d’authentification
Technologies et justifications
L’implémentation repose sur Better-Auth, une bibliothèque d’authentification moderne que j’ai choisie pour ses capacités hybrides JWT/sessions. Cette solution me permet d’explorer une alternative aux approches traditionnelles tout en répondant aux exigences de sécurité identifiées dans la phase de conception.
Architecture modulaire adoptée
J’ai structuré l’implémentation selon une architecture modulaire qui sépare clairement les responsabilités et facilite la maintenance. Cette organisation m’aide à comprendre le rôle de chaque composant dans l’écosystème d’authentification :
modules/auth/├── auth.decorator.ts # Décorateurs pour l'authentification├── auth.entity.ts # Entités complémentaires├── auth.guard.ts # Guard de protection des routes├── auth.module.ts # Configuration du module├── auth.service.ts # Service principal Better-Auth└── README.md # Documentation technique
Cette structuration reflète ma compréhension progressive de l’organisation du code dans une application NestJS professionnelle, compétence que je développe au fil de ce projet.
Configuration et service principal
Implémentation du service Better-Auth
Le cœur du système d’authentification réside dans le service Better-Auth que j’ai configuré pour répondre aux besoins spécifiques de DropIt. Cette configuration m’a demandé d’approfondir ma compréhension des enjeux de sécurité web et de découvrir les subtilités d’une authentification multi-plateforme.
// Configuration Better-Auth adaptée à DropItthis._auth = betterAuth({ secret: config.betterAuth.secret, trustedOrigins: config.betterAuth.trustedOrigins,
// Authentification email/password adaptée au contexte club emailAndPassword: { enabled: true, sendResetPassword: async (data) => { // Intégration avec le service email pour réinitialisation await this.emailService.sendPasswordReset(data); }, },
// Vérification email pour sécuriser les comptes emailVerification: { sendOnSignUp: true, expiresIn: 60 * 60 * 24 * 10, // 10 jours - adapté aux habitudes utilisateur sendVerificationEmail: async (data) => { await this.emailService.sendVerificationEmail(data); }, },
// Connexion PostgreSQL pour cohérence avec l'architecture database: new Pool({ connectionString: config.database.connectionString, }),
// Configuration rate limiting pour protection DDoS rateLimit: { window: 50, max: 100, },
// Hooks personnalisés pour logique métier DropIt hooks: { before: createAuthMiddleware(async (ctx) => { // Hook de pré-traitement pour logs et validation }), },
plugins: [openAPI()], // Documentation automatique des endpoints});
Cette configuration illustre ma démarche d’adaptation d’un outil générique aux besoins spécifiques de DropIt. L’intégration du service email et la définition des paramètres de sécurité reflètent ma compréhension progressive des enjeux de production.
Intégration avec l’écosystème NestJS
L’intégration de Better-Auth dans l’architecture NestJS m’a permis d’explorer les patterns d’injection de dépendances et de découverte de modules. Cette approche facilite la testabilité et la maintenance du code :
// auth.service.ts - Service principal@Injectable()export class AuthService implements OnModuleInit { private _auth: BetterAuth;
constructor( @Inject('EMAIL_SERVICE') private emailService: EmailService, @Inject('CONFIG') private config: Config, ) {}
async onModuleInit() { // Initialisation différée pour gestion des dépendances await this.initialize(); }
get auth(): BetterAuth { return this._auth; }}
Gestion des entités et persistance des données
Modélisation des données d’authentification
L’implémentation de Better-Auth nécessite plusieurs entités complémentaires à l’entité User
existante. Cette modélisation m’a aidé à comprendre la complexité de la gestion des sessions modernes et des systèmes d’authentification distribués.
Entité AuthSession : Gestion des sessions actives
@Entity('auth_session')export class AuthSession { @PrimaryKey() id!: string;
@Property() userId!: string;
@Property({ type: 'text', nullable: true }) impersonatedBy?: string;
@Property() token!: string;
@Property() expiresAt!: Date;
@Property() ipAddress?: string;
@Property() userAgent?: string;
@Property() createdAt = new Date();
@Property({ onUpdate: () => new Date() }) updatedAt = new Date();}
Cette entité me permet de gérer les sessions actives avec un contrôle granulaire sur les métadonnées de connexion. L’intégration des informations d’IP et User-Agent facilite le monitoring et la détection d’activités suspectes.
Entité AuthAccount : Support OAuth futur
@Entity('auth_account')export class AuthAccount { @PrimaryKey() id!: string;
@Property() userId!: string;
@Property() accountId!: string;
@Property() providerId!: string;
@Property({ type: 'json', nullable: true }) accessToken?: string;
@Property({ type: 'json', nullable: true }) refreshToken?: string;
@Property() expiresAt?: Date;
@Property() scope?: string;
@Property({ type: 'json', nullable: true }) idToken?: string;
@Property() createdAt = new Date();
@Property({ onUpdate: () => new Date() }) updatedAt = new Date();}
Bien que non utilisée dans la version initiale de DropIt, cette entité prépare l’évolution future vers l’authentification OAuth (Google, Apple), répondant aux demandes potentielles d’amélioration de l’expérience utilisateur.
Entité AuthVerification : Tokens temporaires
@Entity('auth_verification')export class AuthVerification { @PrimaryKey() id!: string;
@Property() identifier!: string;
@Property() value!: string;
@Property() expiresAt!: Date;
@Property() createdAt = new Date();
@Property({ onUpdate: () => new Date() }) updatedAt = new Date();}
Cette entité gère les tokens de vérification temporaires (email, réinitialisation de mot de passe), avec gestion automatique de l’expiration pour la sécurité.
Protection des routes et système de guards
Implémentation du AuthGuard
Le guard d’authentification constitue le point d’entrée de la sécurisation des routes dans DropIt. Son implémentation m’a permis d’approfondir ma compréhension des intercepteurs NestJS et du cycle de vie des requêtes :
@Injectable()export class AuthGuard implements CanActivate { constructor(private reflector: Reflector, private authService: AuthService) {}
async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest();
// Vérification des métadonnées de route (@Public, @Optional) const isPublic = this.reflector.getAllAndOverride<boolean>('isPublic', [ context.getHandler(), context.getClass(), ]);
const isOptional = this.reflector.getAllAndOverride<boolean>('isOptional', [ context.getHandler(), context.getClass(), ]);
try { // Récupération de la session via Better-Auth const session = await this.authService.auth.api.getSession({ headers: request.headers, });
if (session) { // Enrichissement de la requête avec les données utilisateur request.user = session.user; request.session = session.session; return true; }
// Gestion des routes publiques et optionnelles return isPublic || isOptional || false; } catch (error) { return isPublic || isOptional || false; } }}
Cette implémentation illustre ma compréhension de l’équilibre entre sécurité et flexibilité d’usage, permettant différents niveaux de protection selon les besoins de chaque route.
Décorateurs pour la flexibilité d’usage
L’implémentation de décorateurs personnalisés me permet de simplifier la gestion de l’authentification dans les contrôleurs tout en maintenant une approche déclarative claire :
// auth.decorator.ts - Décorateurs personnalisés
// Marquer une route comme publiqueexport const Public = () => SetMetadata('isPublic', true);
// Authentification optionnelleexport const Optional = () => SetMetadata('isOptional', true);
// Injection de la session dans les paramètresexport const Session = createParamDecorator( (data: unknown, ctx: ExecutionContext) => { const request = ctx.switchToHttp().getRequest(); return data ? request.session?.[data] : request.session; },);
// Hooks pour logique personnaliséeexport const BeforeHook = (hookFn: Function) => SetMetadata('beforeHook', hookFn);export const AfterHook = (hookFn: Function) => SetMetadata('afterHook', hookFn);
Ces décorateurs reflètent ma volonté de créer une API développeur intuitive et maintenable, facilitant l’évolution future du système d’authentification.
Endpoints et API d’authentification
Routes automatiquement exposées par Better-Auth
Better-Auth expose automatiquement plusieurs endpoints sur le préfixe /auth
, réduisant significativement le code à maintenir. Cette approche convention-over-configuration m’a fait apprécier les avantages des frameworks opinionated :
Route | Méthode | Description | Usage dans DropIt |
---|---|---|---|
/auth/signup | POST | Inscription utilisateur | Création comptes coachs/athlètes |
/auth/login | POST | Connexion | Accès quotidien à l’application |
/auth/logout | POST | Déconnexion | Sécurisation des sessions |
/auth/me | GET | Profil utilisateur | Données session courante |
/auth/refresh | POST | Renouvellement token | Maintien des sessions longues |
/auth/verify | GET | Vérification email | Sécurisation des comptes |
/auth/reset-password | POST | Réinitialisation | Récupération comptes oubliés |
Cette standardisation facilite l’intégration côté client et garantit la cohérence des réponses API.
Intégration avec le système d’email
L’intégration du système d’email avec Better-Auth m’a demandé de comprendre l’architecture asynchrone des notifications utilisateur. Cette implémentation prépare l’évolution vers des communications plus riches (notifications push, SMS) :
Patterns d’utilisation dans les contrôleurs
Protection complète d’un contrôleur
L’application du guard au niveau du contrôleur simplifie la sécurisation de l’ensemble des routes d’un module métier :
@Controller('athlete')@UseGuards(AuthGuard) // Protection globale du contrôleurexport class AthleteController { @Get('profile') getProfile(@Session() session) { // Accès automatique aux données de session return { user: session.user, lastLogin: session.session.createdAt, }; }
@Get('public-stats') @Public() // Exception pour route publique getPublicStats() { // Statistiques publiques du club return this.athleteService.getPublicStats(); }}
Authentification optionnelle pour contenu personnalisé
Certaines fonctionnalités de DropIt bénéficient d’une personnalisation selon l’état d’authentification, sans l’exiger absolument :
@Controller('content')@UseGuards(AuthGuard)export class ContentController { @Get('articles') @Optional() // Authentification optionnelle getArticles(@Session() session) { if (session) { // Contenu personnalisé pour utilisateur authentifié return this.contentService.getPersonalizedContent(session.user); } else { // Contenu public pour visiteur anonyme return this.contentService.getPublicContent(); } }}
Gestion des sessions et sécurité
Cycle de vie des sessions
L’implémentation de Better-Auth me permet de gérer finement le cycle de vie des sessions utilisateur, aspect crucial pour la sécurité d’une application de gestion sportive :
Révocation et invalidation
L’architecture hybride choisie facilite la révocation immédiate des sessions, fonctionnalité particulièrement importante dans un contexte où les coachs peuvent avoir besoin de suspendre l’accès d’un athlète :
// Révocation de session - exemple d'usageasync revokeUserSession(userId: string, sessionId?: string) { if (sessionId) { // Révocation d'une session spécifique await this.authService.auth.api.revokeSession({ sessionId }); } else { // Révocation de toutes les sessions utilisateur await this.authService.auth.api.revokeUserSessions({ userId }); }}
Monitoring et observabilité
Hooks pour traçabilité
L’implémentation de hooks me permet d’ajouter des capacités de monitoring et de traçabilité sans altérer la logique core de Better-Auth :
hooks: { before: createAuthMiddleware(async (ctx) => { // Log des tentatives d'authentification this.logger.log(`Auth attempt: ${ctx.request.method} ${ctx.request.url}`); }), after: createAuthMiddleware(async (ctx) => { // Log des authentifications réussies this.logger.log(`Auth success: ${ctx.user?.email}`); }),}
Cette approche facilite le debugging et le monitoring de la sécurité en production.
Perspectives d’évolution et apprentissages
Défis rencontrés et solutions
L’implémentation de Better-Auth m’a confronté à plusieurs défis techniques qui ont enrichi ma compréhension du développement backend :
Intégration multi-plateforme : La gestion des cookies et tokens entre web et mobile m’a demandé d’approfondir ma compréhension des mécanismes d’authentification cross-platform.
Gestion des erreurs : La mise en place d’une gestion d’erreurs robuste m’a sensibilisé à l’importance de l’expérience utilisateur lors des échecs d’authentification.
Performance : L’optimisation des requêtes d’authentification via Redis m’a fait découvrir les enjeux de performance dans les systèmes à forte charge.
Évolutions envisagées
Cette implémentation ouvre plusieurs perspectives d’amélioration que je compte explorer dans l’évolution de DropIt :
- Authentification à deux facteurs : Integration des TOTP pour les comptes administrateurs
- OAuth providers : Support Google/Apple pour simplifier l’onboarding
- Session analytics : Tableaux de bord d’usage pour les administrateurs club
Impact sur ma montée en compétences
Cette implémentation m’a permis de développer une vision pratique de la sécurité applicative, complétant ma formation théorique par une expérience concrète de mise en œuvre. La maîtrise de Better-Auth enrichit mon portfolio technique et me prépare à aborder les enjeux d’authentification dans mes futurs projets professionnels.
Conclusion et transition vers la gestion des autorisations
L’implémentation du système d’authentification de DropIt illustre la complexité pratique de la sécurisation d’une application moderne. Cette base solide prépare maintenant l’étape suivante : la mise en œuvre d’un système de gestion des autorisations granulaire adapté aux rôles spécifiques de l’écosystème haltérophilie.
La section suivante détaillera comment cette fondation d’authentification s’enrichit d’un système RBAC (Role-Based Access Control) permettant de gérer finement les permissions entre coachs, athlètes, et administrateurs, garantissant ainsi que chaque utilisateur accède uniquement aux fonctionnalités et données qui lui sont destinées.