Implémenter une connexion sociale avec Claude Code: Next.js, Auth.js, Google et GitHub OAuth
Guide pratique pour une connexion sociale sûre avec Claude Code, Next.js/Auth.js, Google/GitHub OAuth, code et pièges de production.
La connexion sociale ne se limite pas à ajouter deux boutons sur une page d’inscription. Dès que vous acceptez Google ou GitHub OAuth, vous concevez aussi l’identité utilisateur, l’account linking, les sessions, les cookies, la protection CSRF, les scopes du provider, les journaux d’audit et le support. Demander simplement à Claude Code “ajoute un login” peut produire une interface fonctionnelle, mais aussi laisser une redirect URI incorrecte, une liaison automatique basée sur un email non vérifié, des permissions trop larges ou un client secret dans le code.
Cet article prend Next.js App Router, Auth.js dans le style NextAuth v5, TypeScript et Prisma Adapter comme base. Le authorization code OAuth est un code temporaire échangé côté serveur contre des tokens. state est une valeur aléatoire qui aide à détecter le CSRF. La redirect URI est l’URL exacte vers laquelle Google ou GitHub renvoie le navigateur. Account linking signifie qu’un utilisateur déjà connecté relie explicitement un autre provider à son compte.
Définir d’abord le périmètre de sécurité
La première question n’est pas le nombre de providers, mais ce que la connexion doit prouver. Pour un SaaS, une formation, un outil interne ou un produit développeur, Google et GitHub suffisent souvent. Google convient aux utilisateurs généraux et aux emails d’entreprise. GitHub convient aux communautés techniques et aux produits pour développeurs. Demander Google Drive, Calendar ou GitHub repo au premier login nuit à la confiance et au taux de conversion.
Découpez le travail donné à Claude Code:
- Ajouter les providers Auth.js, les variables d’environnement et la route callback.
- Créer la page de connexion et la page protégée.
- Ajouter seulement
user.idà la session, jamais les access tokens. - Autoriser l’account linking uniquement depuis une page de paramètres avec l’utilisateur déjà connecté.
- Empêcher la suppression du dernier moyen de connexion.
- Ne jamais écrire client secret, refresh token ou access token dans le code, les logs, les tickets ou les brouillons.
Dans une vérification de Masa, le plus gros blocage n’était pas le code, mais une différence entre la redirect URI configurée dans Google Cloud Console et la valeurAUTH_URL de l’application. Claude Code peut modifier le dépôt, mais ne peut pas deviner les valeurs des consoles externes. Mettez donc URL, scopes, règles de vérification email et politique de cookies dans une liste avant l’implémentation.
Visualiser le flux OAuth
La documentation Google recommande l’authorization code flow pour les applications web. Le navigateur reçoit uncode temporaire, puis le serveur l’échange avec le provider. Le client secret ne doit jamais être envoyé au navigateur.
sequenceDiagram
participant User as User
participant App as Next.js app
participant Auth as Auth.js route
participant Provider as Google or GitHub
User->>App: Click "Continue with Google"
App->>Auth: signIn("google")
Auth->>Provider: Redirect with client_id, redirect_uri, scope, state
Provider->>User: Consent screen
Provider->>Auth: Redirect back with code and state
Auth->>Provider: Exchange code on the server
Provider->>Auth: Return tokens
Auth->>App: Create session cookie
App->>User: Show dashboard
state vérifie que le callback correspond bien à la demande de connexion initiale. Auth.js le gère si vous utilisez ses routes standards. Si Claude Code écrit une route callback personnalisée, exigez explicitement la vérification de state. GitHub recommande aussi une valeur imprévisible et l’arrêt du flux en cas de non-correspondance.
Variables d’environnement et scopes minimum
Cette configuration sert à se connecter, pas à obtenir des permissions d’API inutiles. Google utiliseopenid email profile; GitHub utiliseread:user user:email.
npm install next-auth@beta @auth/prisma-adapter prisma @prisma/client
npx prisma init
npm exec auth secret
# .env.local
AUTH_SECRET="valeur générée par npm exec auth secret"
AUTH_URL="http://localhost:3000"
AUTH_GOOGLE_ID="client ID de Google Cloud Console"
AUTH_GOOGLE_SECRET="client secret de Google Cloud Console"
AUTH_GITHUB_ID="client ID de GitHub OAuth App"
AUTH_GITHUB_SECRET="client secret de GitHub OAuth App"
DATABASE_URL="postgresql://user:password@localhost:5432/app"
Le fichier d’exemple ne doit contenir que des clés vides.
# .env.example
AUTH_SECRET=
AUTH_URL=
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
DATABASE_URL=
Pour Google, la redirect URI locale esthttp://localhost:3000/api/auth/callback/google; en production,https://example.com/api/auth/callback/google. Pour GitHub, utilisezhttps://example.com/api/auth/callback/github. Le protocole, le domaine, le chemin et le provider doivent correspondre exactement.
Configuration Auth.js
Le fichier suivant refuse les emails Google non vérifiés et les connexions GitHub qui ne renvoient pas d’email. Les tokens provider restent côté serveur.
// auth.ts
import NextAuth, { type NextAuthConfig } from "next-auth";
import Google from "next-auth/providers/google";
import GitHub from "next-auth/providers/github";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";
type GoogleProfile = {
sub: string;
name?: string;
email: string;
email_verified: boolean;
picture?: string;
};
export const authConfig = {
adapter: PrismaAdapter(prisma),
session: { strategy: "database" },
providers: [
Google({
authorization: {
params: {
scope: "openid email profile",
response_type: "code",
},
},
profile(profile: GoogleProfile) {
return {
id: profile.sub,
name: profile.name,
email: profile.email,
image: profile.picture,
emailVerified: profile.email_verified ? new Date() : null,
};
},
}),
GitHub({
authorization: {
params: {
scope: "read:user user:email",
},
},
}),
],
callbacks: {
async signIn({ account, profile, user }) {
if (account?.provider === "google") {
const googleProfile = profile as GoogleProfile | undefined;
return Boolean(googleProfile?.email && googleProfile.email_verified);
}
if (account?.provider === "github") {
return Boolean(user.email);
}
return true;
},
async session({ session, user }) {
session.user.id = user.id;
return session;
},
},
pages: {
signIn: "/login",
error: "/login",
},
} satisfies NextAuthConfig;
export const { handlers, auth, signIn, signOut } = NextAuth(authConfig);
// src/types/next-auth.d.ts
import "next-auth";
declare module "next-auth" {
interface Session {
user: {
id: string;
name?: string | null;
email?: string | null;
image?: string | null;
};
}
}
// src/app/api/auth/[...nextauth]/route.ts
import { handlers } from "@/auth";
export const { GET, POST } = handlers;
Avec Prisma Adapter, demandez aussi à Claude Code d’ajouter les modèles standardsUser, Account, Session etVerificationToken. La tableAccount permet d’auditer les providers liés à un utilisateur.
Page de connexion et page protégée
Un appel àsignIn depuis une Server Action conserve le flux Auth.js standard et évite de reconstruire manuellement les URL provider.
// src/app/login/page.tsx
import { signIn } from "@/auth";
const providers = [
{ id: "google", label: "Continuer avec Google" },
{ id: "github", label: "Continuer avec GitHub" },
] as const;
export default function LoginPage({
searchParams,
}: {
searchParams: { error?: string };
}) {
return (
<main className="mx-auto flex min-h-screen max-w-sm flex-col justify-center gap-6 px-6">
<div>
<h1 className="text-2xl font-bold">Connexion</h1>
<p className="mt-2 text-sm text-gray-600">
Choisissez le compte professionnel à utiliser pour cette application.
</p>
</div>
{searchParams.error ? (
<p className="rounded-md bg-red-50 p-3 text-sm text-red-700">
Connexion impossible. Essayez un autre compte ou contactez le support.
</p>
) : null}
<div className="grid gap-3">
{providers.map((provider) => (
<form
key={provider.id}
action={async () => {
"use server";
await signIn(provider.id, { redirectTo: "/dashboard" });
}}
>
<button
type="submit"
className="w-full rounded-md border px-4 py-3 text-sm font-medium hover:bg-gray-50"
>
{provider.label}
</button>
</form>
))}
</div>
</main>
);
}
// src/app/dashboard/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const session = await auth();
if (!session?.user) {
redirect("/login");
}
return (
<main className="mx-auto max-w-3xl p-8">
<h1 className="text-2xl font-bold">Dashboard</h1>
<p className="mt-4 text-gray-700">
Signed in as {session.user.email}.
</p>
</main>
);
}
Account linking et révocation
Ne liez pas automatiquement deux comptes parce que l’email correspond. L’utilisateur doit être connecté et lancer l’action depuis les paramètres. L’API de suppression doit vérifier l’origine et bloquer la suppression du dernier moyen de connexion.
// src/app/api/settings/linked-accounts/route.ts
import { auth } from "@/auth";
import { prisma } from "@/lib/prisma";
import { NextResponse } from "next/server";
function isSameOrigin(request: Request) {
const origin = request.headers.get("origin");
const host = request.headers.get("host");
if (!origin || !host) return false;
try {
return new URL(origin).host === host;
} catch {
return false;
}
}
export async function DELETE(request: Request) {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
if (!isSameOrigin(request)) {
return NextResponse.json({ error: "Bad origin" }, { status: 403 });
}
const body = (await request.json()) as { provider?: string };
const accounts = await prisma.account.findMany({
where: { userId: session.user.id },
select: { provider: true },
});
if (accounts.length <= 1) {
return NextResponse.json(
{ error: "Vous ne pouvez pas supprimer le dernier moyen de connexion." },
{ status: 400 },
);
}
await prisma.account.deleteMany({
where: { userId: session.user.id, provider: body.provider },
});
return NextResponse.json({ ok: true });
}
Prompt Claude Code et revue
Ajoute une connexion sociale Google/GitHub à cette app Next.js App Router avec Auth.js v5.
Exigences:
- Lire les client secrets uniquement depuis .env.local ou le secret store de déploiement
- Google scope doit être openid email profile
- GitHub scope doit être read:user user:email
- Google n'est accepté que si email_verified vaut true
- Ajouter seulement user.id à la session et ne jamais exposer access_token au client
- Account linking uniquement depuis une page de paramètres avec utilisateur connecté
- Interdire la suppression du dernier moyen de connexion
- Rapporter les résultats de lint et les étapes de test OAuth manuel
| Point de revue | Ce qu’il faut vérifier |
|---|---|
| OAuth flow | Authorization code flow utilisé et redirect URI identique au dashboard provider |
| state et CSRF | Routes standards Auth.js conservées, API personnalisées avec vérification d’origine |
| Cookie et session | Tokens côté serveur, cookies de production pensés avec Secure, HttpOnly et SameSite |
| Account linking | Email vérifié et action explicite avant liaison |
Cas d’usage concrets
Premier cas: un back-office B2B SaaS. Google devient la voie principale, avec possibilité d’ajouter plus tard une restriction de domaine Workspace et du RBAC. GitHub reste réservé aux profils techniques.
Deuxième cas: un outil développeur. GitHub sert à l’onboarding, puis les permissions repository sont demandées seulement dans la fonctionnalité qui en a besoin.
Troisième cas: un produit existant avec email et mot de passe. Le bon flux consiste à demander à l’utilisateur connecté de lier Google ou GitHub depuis les paramètres, pas à fusionner automatiquement les comptes.
Quatrième cas: une page de formation ou de webinaire. Google verified email réduit les inscriptions douteuses et le travail de confirmation manuelle.
Échecs fréquents en production
La redirect URI incorrecte est le problème le plus courant. Si le local fonctionne mais pas la production, comparezAUTH_URL, les headers Host du proxy et les callback URLs dans Google/GitHub.
La liaison automatique par email est risquée. Google fournitemail_verified, mais tous les providers n’offrent pas la même garantie. Une chaîne email identique ne prouve pas toujours la même identité.
Les scopes excessifs réduisent les vues et les demandes de contact. Un utilisateur qui veut seulement se connecter peut quitter la page si vous demandez l’accès aux dépôts.
Un client secret dans le code doit bloquer la revue. Utilisez.env.local, les secrets de déploiement ou un secret manager.
Les refresh tokens Google doivent être traités séparément. Google peut ne les renvoyer qu’au premier consentement. Pour un login simple, ne les stockez pas; pour des appels API en arrière-plan, créez une tâche dédiée de rotation.
Références officielles et liens internes
Vérifiez les sources primaires: Auth.js, Google Identity Services OAuth, GitHub OAuth Apps et OWASP Authentication Cheat Sheet.
Pour approfondir, lisez implémentation OAuth avec Claude Code, authentification JWT, bonnes pratiques de sécurité Claude Code et gestion des variables d’environnement.
Conseil, formation et points de vérification
ClaudeCodeLab peut aider à transformer un bouton de connexion en flux d’authentification revu: cadrage, tâches Claude Code, revue de code, gestion des secrets et tests OAuth manuels. Pour augmenter les demandes entrantes, définissez d’abord les utilisateurs visés, les providers, les permissions minimales et les messages d’erreur.
Lorsque vous testez cet article, vérifiez que les redirect URI de développement et de production correspondent exactement, que Googleemail_verified est contrôlé, que GitHub sans email public renvoie un message clair, que state et cookies restent dans le flux standard Auth.js, que le dernier moyen de connexion ne peut pas être supprimé et qu’aucun client secret n’apparaît dans le code ou les logs.
PDF gratuit: cheatsheet Claude Code
Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.
Nous protégeons vos données et n'envoyons pas de spam.
À propos de l'auteur
Masa
Ingénieur spécialisé dans les workflows pratiques avec Claude Code.
Articles liés
Workflow Obsidian vers CLAUDE.md avec Claude Code
Transformer des notes Obsidian en notes CLAUDE.md concises pour reprendre les sessions sans réexpliquer.
Claude Code Revenue CTA Routing : relier articles, PDF, Gumroad et consultation
Un workflow Claude Code pour orienter les lecteurs vers PDF gratuit, Gumroad ou consultation selon l'intention.
Règles de handoff Claude Code en équipe: preuves, permissions, rollback et revenus
Un format concret pour transmettre un travail Claude Code avec preuves, permissions, rollback, PDF gratuit, Gumroad et consultation.