Use Cases (Diperbarui: 1/6/2026)

Mengimplementasikan Social Login dengan Claude Code: Next.js, Auth.js, Google, dan GitHub OAuth

Panduan praktis social login aman dengan Claude Code, Next.js/Auth.js, Google/GitHub OAuth, kode siap pakai, dan jebakan produksi.

Mengimplementasikan Social Login dengan Claude Code: Next.js, Auth.js, Google, dan GitHub OAuth

Social login bukan sekadar tombol untuk mempersingkat formulir registrasi. Begitu pengguna masuk lewat Google atau GitHub OAuth, kamu juga sedang mendesain identitas, account linking, session, cookie, CSRF, provider scope, audit log, dan alur support. Jika Claude Code hanya diberi instruksi “buat login”, UI bisa terlihat berjalan, tetapi masih ada risiko: redirect URI salah, akun otomatis terhubung lewat email yang belum diverifikasi, scope terlalu luas, atau client secret masuk ke source code.

Artikel ini memakai Next.js App Router, Auth.js dengan gaya NextAuth v5, TypeScript, dan Prisma Adapter. OAuth authorization code adalah kode sementara yang ditukar server menjadi token. state adalah nilai acak untuk mendeteksi CSRF. Redirect URI adalah URL persis tempat Google atau GitHub mengembalikan browser. Account linking berarti pengguna yang sudah login secara sadar menghubungkan provider lain ke akun yang sama.

Tentukan batas keamanan lebih dulu

Pertanyaan pertama bukan berapa banyak provider yang didukung, tetapi apa yang harus dibuktikan oleh login. Untuk SaaS, halaman pelatihan, tool internal, atau produk developer, Google dan GitHub sering sudah cukup. Google cocok untuk pengguna umum dan email perusahaan. GitHub cocok untuk produk teknis. Meminta Google Drive, Calendar, atau GitHub repo saat login pertama akan menurunkan kepercayaan dan conversion.

Bagi pekerjaan untuk Claude Code menjadi unit kecil:

  • Tambahkan provider Auth.js, environment variables, dan callback route.
  • Buat halaman login dan halaman yang dilindungi.
  • Tambahkan hanya user.id ke session, jangan access token.
  • Account linking hanya dari halaman settings saat pengguna sudah login.
  • Cegah penghapusan metode login terakhir.
  • Jangan menulis client secret, refresh token, atau access token di code, log, issue, atau draft artikel.

Pada proyek uji Masa, masalah terbesar bukan code generation, tetapi redirect URI di Google Cloud Console yang tidak sama denganAUTH_URL aplikasi. Claude Code bisa mengubah repository, tetapi tidak bisa memastikan nilai di console eksternal. Karena itu URL, scope, aturan email verification, dan cookie policy perlu ditulis sebelum implementasi.

Alur OAuth dalam diagram

Dokumentasi Google merekomendasikan authorization code flow untuk aplikasi web. Browser menerimacode sementara, lalu server menukarnya dengan provider. Client secret tidak boleh masuk ke kode browser.

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 memastikan callback berasal dari request login yang dimulai aplikasi. Auth.js menangani ini jika kamu memakai route standar. Jika Claude Code membuat callback custom, validasi state harus disebutkan eksplisit. Dokumentasi GitHub juga menyarankan nilai state yang tidak mudah ditebak dan menghentikan flow bila tidak cocok.

Environment variables dan scope minimum

Konfigurasi ini fokus pada login, bukan mengambil izin API yang belum diperlukan. Google memakaiopenid email profile; GitHub memakairead: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="nilai dari npm exec auth secret"
AUTH_URL="http://localhost:3000"
AUTH_GOOGLE_ID="client ID dari Google Cloud Console"
AUTH_GOOGLE_SECRET="client secret dari Google Cloud Console"
AUTH_GITHUB_ID="client ID dari GitHub OAuth App"
AUTH_GITHUB_SECRET="client secret dari GitHub OAuth App"
DATABASE_URL="postgresql://user:password@localhost:5432/app"

File contoh hanya berisi key kosong, bukan nilai asli.

# .env.example
AUTH_SECRET=
AUTH_URL=
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
DATABASE_URL=

Untuk Google, redirect URI lokal adalahhttp://localhost:3000/api/auth/callback/google; produksi adalahhttps://example.com/api/auth/callback/google. Untuk GitHub gunakanhttps://example.com/api/auth/callback/github. Protocol, domain, path, dan nama provider harus sama persis.

Konfigurasi Auth.js

File berikut menolak Google bilaemail_verified tidak true dan menolak GitHub bila email tidak tersedia. Provider token tidak dikirim ke session browser.

// 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;

Jika memakai Prisma Adapter, minta Claude Code menambahkan model standarUser, Account, Session, danVerificationToken. TabelAccount menyimpan provider dan providerAccountId, sehingga account linking bisa diaudit.

Halaman login dan halaman terlindungi

MemanggilsignIn dari Server Action menjaga flow tetap berada di Auth.js. Ini lebih aman daripada merangkai URL provider secara manual.

// src/app/login/page.tsx
import { signIn } from "@/auth";

const providers = [
  { id: "google", label: "Lanjutkan dengan Google" },
  { id: "github", label: "Lanjutkan dengan 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">Masuk</h1>
        <p className="mt-2 text-sm text-gray-600">
          Pilih identitas kerja yang akan digunakan untuk aplikasi ini.
        </p>
      </div>

      {searchParams.error ? (
        <p className="rounded-md bg-red-50 p-3 text-sm text-red-700">
          Login gagal. Coba akun lain atau hubungi 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>
  );
}

Jangan otomatis menghubungkan akun hanya karena email sama. Pengguna harus sudah login dan memulai linking dari settings. API unlink memeriksa same-origin dan mencegah penghapusan metode login terakhir.

// 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: "Metode login terakhir tidak boleh dihapus." },
      { status: 400 },
    );
  }

  await prisma.account.deleteMany({
    where: { userId: session.user.id, provider: body.provider },
  });

  return NextResponse.json({ ok: true });
}

Prompt Claude Code dan checklist review

Tambahkan Google/GitHub social login ke aplikasi Next.js App Router ini dengan Auth.js v5.
Kebutuhan:
- client secret hanya dibaca dari .env.local atau deployment secrets
- Google scope hanya openid email profile
- GitHub scope hanya read:user user:email
- Google hanya boleh login bila email_verified true
- Session hanya ditambah user.id, jangan expose access_token ke client
- Account linking hanya dari settings page saat user sudah login
- User tidak boleh menghapus metode login terakhir
- Setelah edit, laporkan lint result dan langkah manual OAuth test
Area reviewYang harus dicek
OAuth flowAuthorization code flow dipakai dan redirect URI cocok dengan provider dashboard
state dan CSRFRoute standar Auth.js tetap dipakai, API custom memeriksa same-origin
Cookie dan sessionToken tetap di server; cookie produksi mempertimbangkan Secure, HttpOnly, SameSite
Account linkingEmail verified dan aksi eksplisit pengguna sebelum akun dihubungkan

Contoh use case nyata

Pertama, dashboard admin B2B SaaS. Google menjadi login utama, lalu domain Workspace dan RBAC bisa ditambahkan. GitHub hanya dibuka untuk pengguna teknis.

Kedua, tool untuk developer. GitHub login mempercepat onboarding, sedangkan permission repository diminta nanti di fitur yang benar-benar membutuhkannya.

Ketiga, produk dengan email-password yang ingin menambah social login. Pengguna yang sudah login sebaiknya menghubungkan Google atau GitHub dari settings, bukan otomatis merge berdasarkan email.

Keempat, halaman training atau webinar. Google verified email dapat mengurangi pendaftaran palsu dan biaya konfirmasi manual.

Kegagalan umum di produksi

Redirect URI mismatch adalah masalah paling umum. Jika lokal berhasil tetapi produksi gagal, bandingkanAUTH_URL, proxy Host header, dan callback URL di Google/GitHub.

Automatic linking berdasarkan email itu berisiko. Google menyediakanemail_verified, tetapi tidak semua provider memberi jaminan yang sama. String email yang sama belum cukup sebagai bukti identitas.

Scope berlebihan menurunkan PV dan konsultasi. Pengguna yang hanya ingin login bisa pergi jika melihat permintaan akses repository atau file.

Client secret di code harus menghentikan review. Gunakan.env.local, deployment secrets, atau secret manager.

Refresh token Google perlu desain terpisah. Google bisa mengembalikannya hanya saat consent pertama. Untuk login murni jangan simpan; untuk Google API background buat task token rotation tersendiri.

Gunakan sumber primer: Auth.js, Google Identity Services OAuth, GitHub OAuth Apps, dan OWASP Authentication Cheat Sheet.

Untuk pendalaman, baca implementasi OAuth dengan Claude Code, JWT authentication, security best practices Claude Code, dan manajemen environment variable.

Konsultasi, training, dan poin verifikasi

ClaudeCodeLab membantu tim mengubah tombol login menjadi alur authentication yang bisa direview: requirement, pembagian tugas Claude Code, code review, secret management, dan manual OAuth testing. Jika targetnya meningkatkan inquiry, mulai dari target user, provider, izin minimum, dan pesan error sebelum implementasi.

Saat mencoba isi artikel ini, pastikan redirect URI development dan production sama persis, Googleemail_verified dicek, GitHub tanpa email publik punya pesan error jelas, state dan cookies tetap mengikuti flow standar Auth.js, metode login terakhir tidak bisa dihapus, dan tidak ada client secret di source code atau log.

#Claude Code #social login #OAuth #Auth.js #NextAuth.js #authentication
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.