Better Auth en production : mise en place, pièges et retour d’expérience

· 15 min de lecture
Points clés
  • Better Auth est une bibliothèque TypeScript open source sous licence MIT. Les utilisateurs, les sessions et les organisations restent dans la base de données du produit, sans facturation au nombre d’utilisateurs
  • Better Auth identifie l’utilisateur et son organisation. Les règles d’accès aux données métier, comme savoir qui peut lire telle facture, restent à coder dans l’API
  • Chaque plugin activé (organisations, administration, SSO) ajoute des tables ou des colonnes, à migrer avec l’outil de migration de l’ORM comme toute évolution du schéma
  • Les correctifs de sécurité de Better Auth obligent à monter souvent de version, alors que les versions mineures contiennent parfois des changements cassants. Épinglez la version et testez chaque montée

Better Auth est une bibliothèque d’authentification open source écrite en TypeScript. Elle s’installe dans votre backend, expose les routes de connexion et de gestion des sessions, puis enregistre les utilisateurs dans votre propre base de données. Elle gère les comptes, les sessions et, avec un plugin, les organisations. Les droits sur vos données métier restent à coder dans votre API. Chez Lonestone, Better Auth est notre premier choix sur les nouveaux projets TypeScript. Notre boilerplate open source l’intègre déjà à une API NestJS. Cet article compare Better Auth à Auth.js, Clerk, Supabase Auth et Keycloak, puis liste les problèmes qui apparaissent en production, avec le code de notre intégration.

Le périmètre de Better Auth dans une application TypeScript

Better Auth couvre l’identité de l’utilisateur : inscription par email et mot de passe, connexion avec Google, GitHub ou un autre fournisseur OAuth, vérification de l’email, réinitialisation du mot de passe, sessions et limitation des tentatives de connexion. Les plugins ajoutent la double authentification, les passkeys, les magic links, les organisations avec leurs rôles, l’administration des comptes, le SSO d’entreprise en OIDC ou en SAML et les clés d’API.

La bibliothèque tourne dans votre process Node.js. Elle crée quatre tables dans votre base (user, session, account, verification) et répond sur un préfixe de routes, /api/auth/* par défaut. Elle se branche sur NestJS, Express, Hono ou Next.js. Côté front, un client typé appelle ces routes : authClient.signIn.email() pour se connecter, authClient.useSession() pour lire la session dans un composant React. Le plugin inferAdditionalFields reprend dans le client les champs que vous avez ajoutés à l’utilisateur côté serveur, sans les redéclarer.

Better Auth vous laisse quatre chantiers :

  • Votre API contrôle les droits sur les données. Better Auth sait qui est connecté et à quelle organisation il appartient. À vous de vérifier que la facture demandée appartient bien à cette organisation. L’oubli de cette vérification, appelé BOLA, est la première faille du Top 10 OWASP des API.
  • Vous branchez l’envoi des emails. Better Auth appelle une fonction sendVerificationEmail ou sendResetPassword, que vous reliez à votre service d’envoi.
  • Vous construisez les écrans de connexion et d’inscription. Clerk, lui, fournit des composants prêts à l’emploi.
  • Vous gérez l’exploitation : la base, les sauvegardes, le stockage des compteurs de tentatives et les montées de version.

Better Auth face à Auth.js, Clerk, Supabase Auth et Keycloak

En démo, ces cinq solutions connectent un utilisateur en quelques minutes. Les différences apparaissent en production, sur trois questions : où sont stockés les comptes, combien coûte chaque nouvel utilisateur, et comment connecter un client grand compte à son annuaire d’entreprise.

Better AuthAuth.jsClerkSupabase AuthKeycloak
NatureBibliothèque TypeScript dans votre backendBibliothèque TypeScript, en maintenanceService hébergéService de la plateforme SupabaseServeur Java à héberger
Stockage des comptesVotre baseVotre baseInfrastructure de ClerkBase Postgres SupabaseBase de Keycloak
CoûtGratuit (licence MIT)GratuitGratuit jusqu’à 50 000 utilisateurs actifs par mois, puis 0,02 $ par utilisateur en offre ProGratuit jusqu’à 50 000 utilisateurs actifs par mois. L’offre Pro en inclut 100 000, puis 0,00325 $ par utilisateurGratuit, avec l’hébergement et l’exploitation à votre charge
Organisations et rôlesPlugin organization (rôles, équipes, invitations)À coderInclus, 100 organisations puis 1 $ par mois chacuneÀ coder, avec la sécurité au niveau des lignes de PostgresRealms, groupes et rôles
SSO SAMLPlugin sso (OIDC et SAML 2.0)Via un service tiersUne connexion incluse, puis 75 $ par mois chacuneSur les offres payantesNatif, avec LDAP

Auth.js, l’ancien NextAuth, a rejoint Better Auth en septembre 2025. Son équipe corrige toujours les failles de sécurité, mais elle recommande Better Auth pour les nouveaux projets et publie un guide de migration. Sur un projet existant sous Auth.js, la migration peut attendre la prochaine refonte de l’authentification.

Un projet démarre plus vite avec Clerk, grâce à ses composants de connexion, son tableau de bord et son SSO configurable en quelques clics. En contrepartie, la facture augmente avec le nombre d’utilisateurs. Clerk est aussi un sous-traitant, que vous devez déclarer quand un client B2B demande où sont stockés ses comptes. Supabase Auth est un bon choix si le produit tourne déjà sur Supabase. Keycloak reste la référence quand plusieurs applications, dont certaines hors TypeScript, partagent un même fournisseur d’identité. Il faut alors héberger et mettre à jour un serveur Java de plus.

Vercel a racheté Better Auth en juillet 2026. Selon l’annonce, l’équipe se concentre sur la bibliothèque open source, qui reste sous licence MIT, plutôt que sur une offre d’authentification hébergée.

Sur un SaaS TypeScript, nous choisissons Better Auth par défaut, pour garder les comptes dans la base du produit et typer l’authentification du serveur jusqu’au front. Nous passons à Keycloak quand le client impose un fournisseur d’identité commun à plusieurs applications.

Comparatif de Better Auth, Auth.js, Clerk, Supabase Auth et Keycloak : nature de la solution, lieu de stockage des comptes et coût

Mettre en place Better Auth : schéma, sessions, organisations et rôles

Le code qui suit vient de notre boilerplate, qui monte Better Auth dans une API NestJS avec PostgreSQL et MikroORM. Nous l’avons simplifié pour la lecture.

La configuration du serveur

import { betterAuth } from 'better-auth'
import { mikroOrmAdapter } from './auth-db.adapter'
export function createBetterAuth(options: BetterAuthOptionsDynamic) {
return betterAuth({
baseURL: options.baseUrl,
secret: options.secret,
trustedOrigins: options.trustedOrigins,
database: mikroOrmAdapter(options.orm),
emailAndPassword: {
enabled: true,
autoSignIn: false,
sendResetPassword: options.sendResetPassword,
},
emailVerification: {
sendOnSignUp: true,
expiresIn: 60 * 60 * 24 * 10, // lien valable 10 jours
sendVerificationEmail: options.sendVerificationEmail,
},
advanced: {
database: { generateId: false }, // Postgres génère les UUID
},
rateLimit: { window: 50, max: 100 },
})
}

trustedOrigins liste les domaines du front autorisés à appeler l’API d’authentification et à servir de destination aux redirections. Limitez-le aux domaines de production et de préproduction. Avec autoSignIn: false, l’utilisateur se connecte lui-même après l’inscription, une fois l’email de vérification reçu. generateId: false laisse Postgres générer les identifiants, pour que les tables d’authentification suivent la même convention que les tables métier.

Le schéma de base

La CLI de Better Auth génère le schéma attendu par votre configuration (npx auth generate). Avec l’adaptateur Kysely intégré, npx auth migrate crée directement les tables. Avec Prisma, Drizzle ou MikroORM, la CLI produit le schéma, puis l’outil de migration de votre ORM l’applique comme n’importe quelle autre table. Les quatre tables de base contiennent :

  • user : le nom, l’email, l’état de vérification de l’email et l’avatar
  • session : le jeton, la date d’expiration, l’adresse IP, le navigateur et l’utilisateur
  • account : une ligne par méthode de connexion, avec le mot de passe haché ou les identifiants du fournisseur OAuth
  • verification : les jetons de vérification d’email et de réinitialisation du mot de passe

Les sessions

Better Auth stocke les sessions en base, là où d’autres bibliothèques signent un JWT. Le cookie contient un jeton, avec lequel le serveur retrouve la session à chaque requête. Par défaut, une session dure sept jours et se prolonge quand l’utilisateur revient après plus d’un jour. Dans NestJS, un guard lit la session à chaque requête :

@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private readonly reflector: Reflector,
private readonly authService: AuthService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest()
const session = await this.authService.api.getSession({
headers: fromNodeHeaders(request.headers),
})
request.session = session
if (this.reflector.get('PUBLIC', context.getHandler())) return true
if (this.reflector.get('OPTIONAL', context.getHandler()) && !session) return true
if (!session) throw new UnauthorizedException()
return true
}
}

Un décorateur @Session() transmet ensuite la session au contrôleur :

@Controller('posts')
@UseGuards(AuthGuard)
export class PostController {
constructor(private readonly postService: PostService) {}
@Post()
async createPost(
@Session() session: LoggedInBetterAuthSession,
@Body() body: CreatePostInput,
) {
return this.postService.createPost(session.user.id, body)
}
}

Les organisations, les rôles et le multi-tenant

Sur un SaaS B2B, le plugin organization ajoute trois tables (organization, member, invitation) et un champ activeOrganizationId sur la session. Chaque membre reçoit un rôle, owner, admin ou member par défaut. Les invitations par email expirent au bout de 48 heures. Pour des droits propres à votre produit, déclarez vos ressources et leurs actions avec createAccessControl() :

import { createAccessControl } from 'better-auth/plugins/access'
import { adminAc, defaultStatements } from 'better-auth/plugins/organization/access'
const statement = {
...defaultStatements,
project: ['create', 'update', 'delete'],
invoice: ['read', 'export'],
} as const
export const ac = createAccessControl(statement)
export const admin = ac.newRole({
...adminAc.statements,
project: ['create', 'update', 'delete'],
invoice: ['read', 'export'],
})
export const accountant = ac.newRole({ invoice: ['read', 'export'] })

Passez ensuite ces rôles au plugin (organization({ ac, roles: { owner, admin, member, accountant } })), côté serveur comme côté client.

Le plugin gère les membres et leurs rôles, mais il ignore vos tables métier. Dans une architecture multi-tenant à base partagée, chaque table métier porte un organizationId, que chaque requête compare à l’organisation active de la session :

const organizationId = request.session.session.activeOrganizationId
if (!organizationId) throw new ForbiddenException()
const project = await this.em.findOne(Project, {
id: request.params.projectId,
organization: { id: organizationId },
})
if (!project) throw new NotFoundException()

Renvoyez une 404 plutôt qu’une 403 quand la ressource appartient à une autre organisation, pour qu’un client ne sache même pas que les projets des autres clients existent.

graph TD
  A[Navigateur<br/>cookie de session] --> B{Route /api/auth/* ?}
  B -->|oui| C[Handler Better Auth<br/>connexion, inscription, organisations]
  B -->|non| D[AuthGuard NestJS<br/>getSession]
  D -->|pas de session| E[Réponse 401]
  D -->|session valide| F[Contrôleur<br/>user.id et activeOrganizationId]
  F --> G[Requête métier<br/>filtrée par organizationId]

Les pièges de Better Auth en production

Les montées de version

Better Auth évolue vite, au point que ses versions mineures contiennent parfois des changements cassants. La version 1.5 a déplacé les adaptateurs de base de données et le plugin de clés d’API dans des paquets séparés. La 1.7, sortie en juin 2026, a remanié le modèle des comptes, remplacé le plugin oidcProvider par un paquet dédié et activé PKCE par défaut. Épinglez la version exacte, lisez le changelog avant chaque montée et couvrez l’inscription, la connexion et les invitations par des tests d’intégration.

Les migrations à chaque plugin

Chaque plugin ajoute des tables ou des colonnes. Quand vous activez les organisations sur un produit déjà en production, le plugin ajoute activeOrganizationId à la session et crée trois tables vides. Chaque utilisateur existant doit alors recevoir une organisation, sinon il se retrouve sans espace de travail à sa prochaine connexion. Écrivez cette reprise de données comme une migration ordinaire et testez-la sur une copie de la base de production.

La révocation des sessions

Vous pouvez révoquer immédiatement une session stockée en base. revokeSession, revokeOtherSessions et revokeSessions suppriment les lignes, donc la requête suivante échoue. Le cache de session dans un cookie (cookieCache) évite une lecture en base à chaque requête, avec une contrepartie : une session supprimée reste acceptée jusqu’à l’expiration du cache. Si vous l’activez, gardez une durée de quelques minutes et relisez la session en base avant les actions sensibles, comme un changement d’email ou une suppression de compte (getSession avec disableCookieCache: true).

Le rate limit sur plusieurs instances

Par défaut, Better Auth garde les compteurs de tentatives en mémoire. Dès que l’API tourne sur deux instances ou en serverless, chaque instance compte de son côté, donc la limite se multiplie par le nombre d’instances. Stockez les compteurs en base ou dans Redis. Les appels faits côté serveur via auth.api échappent à cette limite, donc gardez-les pour du code de confiance.

Le SSO d’entreprise

Un client grand compte finit souvent par demander que ses équipes se connectent avec leur compte Microsoft Entra ID ou Okta. Le plugin @better-auth/sso gère OIDC et SAML 2.0, la vérification du domaine de l’entreprise et le rattachement automatique des utilisateurs à leur organisation. Il vous reste la configuration de chaque client : son annuaire, ses attributs, la correspondance entre ses groupes et vos rôles. Prévoyez un écran d’administration ou une procédure pour la saisir. Testez aussi avec un vrai tenant Entra ID ou Okta, car le format des attributs varie d’un fournisseur SAML à l’autre. Comparez ce travail au prix d’un service : WorkOS facture 125 $ par mois et par connexion, Clerk 75 $ par mois au-delà de la première connexion.

Les failles de sécurité

Les failles d’une bibliothèque d’authentification sont souvent critiques. Better Auth en a corrigé plusieurs. L’une d’elles permettait de créer une clé d’API pour n’importe quel utilisateur sans être connecté (CVE-2025-61928, corrigée en version 1.3.26). En juin 2026, l’équipe a publié quinze correctifs en une fois, dont deux critiques, sur le cœur, le SSO, le SCIM et les organisations. Comme le code est ouvert, ces failles sont repérées et corrigées vite. Il vous reste à suivre les avis de sécurité du dépôt GitHub : activez Renovate ou Dependabot sur le paquet et appliquez les correctifs dans la semaine.

La conformité

Comme les comptes restent dans votre base, l’authentification n’ajoute aucun sous-traitant, ce qui simplifie la conformité au RGPD. Si votre base est hébergée en Europe, les comptes le sont aussi. Deux points restent à coder. Quand un utilisateur supprime son compte, effacez aussi ses données métier. Pour tenir un journal des connexions et des changements de droits, partez des hooks de Better Auth.

Checklist avant de mettre Better Auth en production : version épinglée, trustedOrigins limité, rate limit partagé, cache de session court, filtrage par organisation et suivi des avis de sécurité

Better Auth dans le boilerplate Lonestone

Notre boilerplate open source est le socle technique de nos projets web : une API NestJS, un front React, PostgreSQL avec MikroORM et des briques IA déjà câblées. L’authentification y repose sur Better Auth, avec :

  • un adaptateur MikroORM écrit par l’équipe, qui remplace le paquet communautaire, et une commande qui génère les entités à partir des plugins actifs (pnpm --filter=api auth:generate)
  • un module NestJS qui monte le handler Better Auth sur /api/auth/*, l’AuthGuard et les décorateurs @Public(), @Optional() et @Session()
  • des décorateurs @BeforeHook() et @AfterHook() qui branchent une méthode d’un service NestJS sur une route d’authentification, pour réagir à une inscription par exemple
  • l’inscription par email avec vérification et la réinitialisation du mot de passe, reliées au module d’envoi d’emails
  • la documentation OpenAPI des routes d’authentification, servie sur /api/auth/reference
  • un client React dont les types suivent la configuration du serveur

Les organisations, les équipes et l’administration des comptes ont chacune leur guide pas à pas dans la documentation du boilerplate. Nous les activons au cas par cas, parce qu’un outil interne à une seule entreprise n’en a pas besoin et que chaque plugin ajoute des tables.

Ce socle couvre l’authentification dès le premier jour d’un projet. La logique métier se construit par-dessus : les rôles propres au produit, les règles d’accès par client, l’onboarding des nouvelles organisations. Nos ingénieurs, qui ont pour la plupart entre 10 et 25 ans d’expérience, s’en chargent quand nous créons un SaaS pour un éditeur ou une startup. Ils s’en chargent aussi quand nous intégrons de l’IA dans un logiciel existant, où les agents doivent respecter les mêmes droits que les utilisateurs qu’ils servent.

FAQ

Questions fréquentes

Better Auth est-il gratuit ?

Oui. Better Auth est une bibliothèque open source sous licence MIT, sans facturation au nombre d’utilisateurs, puisque les comptes et les sessions sont stockés dans la base de données de l’application. Le coût se limite à l’hébergement de cette base et au temps de développement. Une offre payante optionnelle, Better Auth Infrastructure, ajoute un tableau de bord et des journaux d’audit. Les services hébergés comme Clerk, eux, facturent au-delà de 50 000 utilisateurs actifs par mois.

Faut-il choisir Better Auth ou Auth.js (NextAuth) ?

Pour un nouveau projet, Better Auth. Auth.js a rejoint Better Auth en septembre 2025 et ne reçoit plus que les correctifs de sécurité et les corrections urgentes. Son équipe recommande Better Auth pour les nouveaux projets et publie un guide de migration. Sur une application existante sous Auth.js, la migration peut attendre une refonte de l’authentification. Better Auth propose aussi des plugins qu’Auth.js n’a pas : organisations, rôles, double authentification, SSO SAML.

Better Auth ou Clerk : lequel choisir pour un SaaS ?

Clerk est un service hébergé qui fournit des écrans de connexion prêts à l’emploi et un tableau de bord. Un projet démarre plus vite avec Clerk, mais la facture augmente avec le nombre d’utilisateurs et de connexions SSO. Better Auth est une bibliothèque installée dans le backend : les comptes restent dans la base de l’application, sans coût par utilisateur, mais les écrans de connexion sont à construire. Pour un SaaS B2B dont les clients posent des questions sur le stockage des données, Better Auth évite d’ajouter un sous-traitant.

Better Auth fonctionne-t-il avec NestJS ?

Oui. Le handler Node.js de Better Auth se monte comme un middleware NestJS sur les routes d’authentification. Sur les autres routes, un guard lit la session à chaque requête avec auth.api.getSession(). Le boilerplate open source de Lonestone fournit cette intégration : module NestJS, guard, décorateurs @Session() et @Public(), adaptateur MikroORM et hooks d’authentification. Better Auth fonctionne aussi avec Next.js, Express et Hono.

Better Auth gère-t-il le multi-tenant ?

En partie. Le plugin organization gère les organisations, les membres, les rôles, les équipes et les invitations, et enregistre l’organisation active dans la session. L’isolation des données métier reste à coder : dans une architecture multi-tenant à base partagée, chaque table porte un identifiant d’organisation et chaque requête de l’API filtre sur l’organisation active de l’utilisateur.

Better Auth est-il sécurisé pour une application en production ?

Oui, avec une discipline de mise à jour. Better Auth stocke des sessions révocables en base, limite les tentatives de connexion et vérifie l’origine des requêtes. La bibliothèque a corrigé plusieurs failles critiques en 2025 et 2026. En juin 2026, son équipe a publié quinze correctifs d’un coup, dont deux critiques. Une équipe qui l’utilise en production épingle la version, suit les avis de sécurité du dépôt GitHub et applique les correctifs rapidement. Les droits d’accès aux données métier restent à vérifier dans l’API, pour éviter les failles décrites dans le Top 10 OWASP des API.

On discute de votre projet ?

Échange gratuit et sans engagement, directement avec un expert du sujet. Devis sous 48h.

Contacter l'équipe
de Lonestone