Authentification
Configuration de l'authentification avec email/mot de passe, fournisseurs OAuth, gestion des sessions et protection des routes.
Vue d'ensemble
ScaleRocket utilise Supabase Auth pour l'authentification. Il prend en charge la connexion par email/mot de passe, les fournisseurs OAuth (Google, GitHub), la réinitialisation du mot de passe et la gestion automatique des sessions.
Supabase gère toute la logique d'authentification côté serveur. Le SDK client gère les tokens et le rafraîchissement des sessions automatiquement.
ScaleRocket utilise Convex Auth pour l'authentification. Il prend en charge la connexion par email/mot de passe, les fournisseurs OAuth (Google, GitHub) et la gestion automatique des sessions.
Convex Auth est construit sur la bibliothèque @convex-dev/auth et gère toute la logique d'authentification côté serveur.
Les pages d'authentification se trouvent dans apps/app/src/pages/auth/.
Architecture d'authentification
User -> Login Page -> Supabase Auth -> JWT Token -> App
-> Trigger: create profile
-> Session stored in browserUser -> Login Page -> Convex Auth -> Session Token -> App
-> Mutation: create profile
-> Session managed by ConvexPages de connexion et d'inscription
Inscription
Située dans apps/app/src/pages/auth/register.tsx :
import { supabase } from "@/lib/supabase";
const { data, error } = await supabase.auth.signUp({
email,
password,
options: {
data: {
full_name: name,
},
},
});Située dans apps/app/src/pages/auth/register.tsx :
import { useAuthActions } from "@convex-dev/auth/react";
const { signIn } = useAuthActions();
await signIn("password", { email, password, name, flow: "signUp" });Connexion
Située dans apps/app/src/pages/auth/login.tsx :
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});Située dans apps/app/src/pages/auth/login.tsx :
import { useAuthActions } from "@convex-dev/auth/react";
const { signIn } = useAuthActions();
await signIn("password", { email, password, flow: "signIn" });Fournisseurs OAuth
Google et GitHub
const { data, error } = await supabase.auth.signInWithOAuth({
provider: "google", // or "github"
options: {
redirectTo: `${window.location.origin}/auth/callback`,
},
});import { useAuthActions } from "@convex-dev/auth/react";
const { signIn } = useAuthActions();
// Google
await signIn("google");
// GitHub
await signIn("github");Ajouter un nouveau fournisseur OAuth
- Activez le fournisseur dans votre tableau de bord Supabase sous Authentication > Providers.
- Ajoutez l'identifiant client et le secret depuis la console développeur du fournisseur.
- Ajoutez un bouton dans les pages de connexion/inscription :
<Button onClick={() => signInWithOAuth("discord")}>
Continue with Discord
</Button>- Configurez le fournisseur dans
convex/auth.config.ts. - Ajoutez l'identifiant client et le secret comme variables d'environnement.
- Ajoutez un bouton dans les pages de connexion/inscription :
<Button onClick={() => signIn("discord")}>
Continue with Discord
</Button>Callback d'authentification
La page de callback dans apps/app/src/pages/auth/callback.tsx échange le code OAuth contre une session :
const { data, error } = await supabase.auth.exchangeCodeForSession(code);Convex gère le callback OAuth automatiquement. Aucun échange de code manuel n'est nécessaire -- la bibliothèque @convex-dev/auth gère le flux de callback.
Flux de réinitialisation du mot de passe
- L'utilisateur demande une réinitialisation depuis la page de connexion :
await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${window.location.origin}/auth/reset-password`,
});import { useAuthActions } from "@convex-dev/auth/react";
const { signIn } = useAuthActions();
await signIn("password", { email, flow: "reset" });-
L'utilisateur clique sur le lien dans l'email et arrive sur la page de réinitialisation.
-
L'utilisateur définit un nouveau mot de passe :
await supabase.auth.updateUser({ password: newPassword });await signIn("password", { email, password: newPassword, code, flow: "reset-verification" });Gestion des sessions
Le client Supabase gère automatiquement les sessions :
// Get current session
const { data: { session } } = await supabase.auth.getSession();
// Listen for auth state changes
supabase.auth.onAuthStateChange((event, session) => {
if (event === "SIGNED_IN") {
// redirect to dashboard
}
if (event === "SIGNED_OUT") {
// redirect to login
}
});Les sessions sont stockées dans localStorage et rafraîchies automatiquement avant expiration.
Convex gère les sessions automatiquement via le ConvexAuthProvider :
import { useConvexAuth } from "convex/react";
const { isAuthenticated, isLoading } = useConvexAuth();
// Côté serveur (dans les fonctions Convex) :
import { getAuthUserId } from "@convex-dev/auth/server";
const userId = await getAuthUserId(ctx);Les sessions sont gérées côté serveur par Convex. Aucune gestion manuelle des tokens n'est nécessaire.
Protection des routes
Protégez les routes en utilisant un composant de garde d'authentification :
// apps/app/src/components/auth-guard.tsx
import { useAuth } from "@/hooks/use-auth";
import { Navigate } from "react-router-dom";
export function AuthGuard({ children }: { children: React.ReactNode }) {
const { user, loading } = useAuth();
if (loading) return <LoadingSpinner />;
if (!user) return <Navigate to="/auth/login" />;
return children;
}Protégez les routes en utilisant le hook d'authentification Convex :
// apps/app/src/components/auth-guard.tsx
import { useConvexAuth } from "convex/react";
import { Navigate } from "react-router-dom";
export function AuthGuard({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useConvexAuth();
if (isLoading) return <LoadingSpinner />;
if (!isAuthenticated) return <Navigate to="/auth/login" />;
return children;
}Encapsulez les routes protégées :
<Route
path="/dashboard"
element={
<AuthGuard>
<Dashboard />
</AuthGuard>
}
/>Le hook useAuth
// apps/app/src/hooks/use-auth.ts
export function useAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setUser(session?.user ?? null);
setLoading(false);
});
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setUser(session?.user ?? null);
}
);
return () => subscription.unsubscribe();
}, []);
return { user, loading };
}// apps/app/src/hooks/use-auth.ts
import { useConvexAuth } from "convex/react";
import { useQuery } from "convex/react";
import { api } from "../../convex/_generated/api";
export function useAuth() {
const { isAuthenticated, isLoading } = useConvexAuth();
const user = useQuery(api.users.getMe);
return {
user: isAuthenticated ? user : null,
loading: isLoading,
};
}Suppression de compte
ScaleRocket inclut une fonctionnalité de suppression de compte qui gère le nettoyage complet du compte. Les utilisateurs peuvent supprimer leur compte depuis Settings > Danger Zone dans le tableau de bord.
Fonctionnement
La Edge Function delete-account effectue les étapes suivantes dans l'ordre :
- Annule l'abonnement Stripe -- Si l'utilisateur a un abonnement actif, il est annulé immédiatement via l'API Stripe.
- Supprime les données utilisateur -- Supprime tous les enregistrements liés à l'utilisateur de la base de données (profil, abonnement, crédits, etc.).
- Supprime l'utilisateur auth -- Supprime l'utilisateur de Supabase Auth en utilisant le client service role.
L'action Convex deleteAccount effectue les étapes suivantes dans l'ordre :
- Annule l'abonnement Stripe -- Si l'utilisateur a un abonnement actif, il est annulé immédiatement via l'API Stripe.
- Supprime les données utilisateur -- Supprime tous les enregistrements liés à l'utilisateur de la base de données (profil, abonnement, crédits, etc.).
- Supprime l'utilisateur auth -- Supprime la session et les données d'authentification de l'utilisateur.
Utilisation
La fonction nécessite un paramètre confirmEmail qui doit correspondre à l'adresse email de l'utilisateur pour éviter une suppression accidentelle :
const { data, error } = await supabase.functions.invoke("delete-account", {
body: {
confirmEmail: user.email,
},
});Si l'email fourni ne correspond pas à l'email de l'utilisateur authentifié, la fonction renvoie une erreur 400.
La mutation nécessite un paramètre confirmEmail qui doit correspondre à l'adresse email de l'utilisateur pour éviter une suppression accidentelle :
import { useMutation } from "convex/react";
import { api } from "../../convex/_generated/api";
const deleteAccount = useMutation(api.users.deleteAccount);
await deleteAccount({ confirmEmail: user.email });Personnalisation des pages d'authentification
Les pages d'authentification utilisent des composants de packages/ui. Pour personnaliser :
- Style : Modifiez les composants de formulaire dans
apps/app/src/pages/auth/. - Champs : Ajoutez des champs au formulaire d'inscription -- ils sont stockés dans
raw_user_meta_data. - Redirection : Changez la redirection post-connexion dans le gestionnaire de callback d'authentification.
- Modèles d'email : Personnalisez les emails de confirmation/réinitialisation dans le tableau de bord Supabase sous Authentication > Email Templates.
Fini ? Marquez cette page comme terminée.