Social Login — Auth

Social Login memungkinkan user mendaftar dan login menggunakan akun mereka di platform lain (Google, GitHub, Facebook, dll) tanpa harus membuat password baru…

Social login adalah login memakai akun yang sudah kamu punya di layanan lain, misalnya Google, jadi gak perlu password baru. Bayangin acara antarsekolah. Panitia gak membuat kartu tanda pengenal baru untukmu. Mereka melihat kartu pelajar yang dikeluarkan sekolahmu, mengecek kartunya asli, sekolah penerbitnya benar, ditujukan untuk acara ini, dan belum kedaluwarsa, lalu mencocokkan nomor induknya dengan daftar peserta. Di social login, kartu itu namanya id_token, penerbitnya Google, dan nomor induknya klaim sub.

🧪 Tebakan cepat: Siti sudah punya akun Portal Sekolah dengan email [email protected]. Dia menekan "Login dengan Google" untuk pertama kali, dan akun Google-nya memakai email yang sama, sudah terverifikasi. Portal sebaiknya membuat akun baru, atau menyambungkan ke akun Siti yang lama? Tebak dulu, jawabannya ada di bagian "Menyambungkan ke akun".

OAuth + OpenID Connect

Lesson OAuth 2.0 memberi Portal Sekolah izin memakai kalender Pak Andi. Itu authorization. Untuk login, Portal butuh hal lain: siapa yang baru saja login. Access token gak menjawab itu, karena dia cuma kunci untuk memanggil API.

OpenID Connect (OIDC) adalah lapisan di atas OAuth 2.0 yang menambahkan identitas. Alurnya sama persis (authorization code, state, PKCE), bedanya dua:

Jadi di balik tombol "Login dengan Google" bekerja OAuth 2.0 untuk otorisasi, plus OpenID Connect untuk identitas. Ini payload id_token Siti, persis seperti di Lab (login 9 Oktober 2026 jam 07.00 WIB):

{
  "iss": "https://accounts.google.com",
  "aud": "1234567890-portal.apps.googleusercontent.com",
  "sub": "110169484474386276334",
  "email": "[email protected]",
  "email_verified": true,
  "name": "Siti",
  "iat": 1791504000,
  "exp": 1791507600
}

Cek id_token, berurutan

Membaca payload belum berarti percaya. Server memeriksanya dengan urutan ini dan berhenti di pemeriksaan pertama yang gagal:

Urutan Klaim Harus Kalau gagal
1 tanda tangan cocok dengan public key Google (https://www.googleapis.com/oauth2/v3/certs) token palsu atau diubah
2 iss https://accounts.google.com (atau accounts.google.com) bukan dari Google
3 aud client_id Portal Sekolah token itu dibuat untuk aplikasi lain
4 exp lebih besar dari waktu sekarang, dalam detik Unix sudah kedaluwarsa
5 sub ada gak ada ID akun

Tanda tangan diperiksa library dengan kunci publik Google, seperti JWT di lesson sebelumnya, cuma algoritmanya RS256. Klaim-klaimnya:

const GOOGLE_CLIENT_ID = "1234567890-portal.apps.googleusercontent.com";

function decodePayload(idToken) {
  const part = idToken.split(".")[1].replace(/-/g, "+").replace(/_/g, "/");
  return JSON.parse(atob(part)); // cuma membaca, belum memverifikasi
}

function checkClaims(claims, nowSeconds) {
  if (claims.iss !== "https://accounts.google.com" && claims.iss !== "accounts.google.com") return "iss";
  if (claims.aud !== GOOGLE_CLIENT_ID) return "aud";
  if (claims.exp <= nowSeconds) return "exp";
  if (!claims.sub) return "sub";
  return null; // lolos
}

Menyambungkan ke akun

Setelah token lolos, Portal mencari user-nya dengan urutan ini:

function findOrLink(db, claims) {
  const social = db.socialAccounts.find((s) => s.provider === "google" && s.providerId === claims.sub);
  if (social) return db.users.find((u) => u.id === social.userId); // sudah pernah: cari lewat sub
  if (claims.email_verified !== true) return { error: "email belum terverifikasi" };

  let user = db.users.find((u) => u.email === claims.email);
  if (!user) {
    user = { id: db.nextId++, name: claims.name, email: claims.email, role: "student" };
    db.users.push(user);
  }
  db.socialAccounts.push({ userId: user.id, provider: "google", providerId: claims.sub });
  return user;
}
  1. Lewat sub di tabel social_accounts (kolom user_id, provider, provider_id). sub gak pernah berubah untuk satu akun Google, sedangkan email bisa diganti.
  2. Lewat email, hanya kalau email_verified bernilai true. Email yang belum diverifikasi belum terbukti milik orang itu, jadi gak boleh menyambungkan ke akun siapa pun.
  3. Belum ada sama sekali: buat akun baru dari data Google (nama, email), dengan role paling rendah, lalu sambungkan ke sub-nya.

Hasilnya di Lab:

id_token Dicari lewat Hasil
Siti, pertama kali sub belum ada, email terverifikasi cocok dengan user 1 baris baru di social_accounts, masuk sebagai Siti
Siti, kedua kali sub ketemu masuk sebagai Siti, email gak dilihat
Nadia, murid baru sub dan email gak ketemu user 5 dibuat (role student) lalu disambungkan
[email protected], email_verified: false sub belum ada, email belum terverifikasi gak disambungkan ke akun Pak Andi

Jadi untuk Siti, jawabannya menyambungkan ke akun lama, karena email-nya sama dan terverifikasi. Itu jawaban tebakannya. Nadia dapat id 5, bukan 4, karena id 4 dulu milik Rizky dan id auto-increment gak dipakai ulang.

Di Laravel: Socialite

Laravel Socialite mengerjakan alur OAuth dan OIDC-nya. Untuk Google, scope default-nya sudah openid, profile, email.

// routes/api.php
Route::get('/auth/google/redirect', fn () => Socialite::driver('google')->stateless()->redirect());

Route::get('/auth/google/callback', function () {
    $google = Socialite::driver('google')->stateless()->user();

    $user = SocialAccount::firstWhere(['provider' => 'google', 'provider_id' => $google->getId()])?->user;
    if (! $user) {
        abort_unless(($google->getRaw()['email_verified'] ?? false) === true, 403, 'Email Google belum terverifikasi.');
        $user = User::firstOrCreate(['email' => $google->getEmail()], ['name' => $google->getName(), 'role' => 'student']);
        $user->socialAccounts()->create(['provider' => 'google', 'provider_id' => $google->getId()]);
    }

    return AuthResponse::for($user); // access token + cookie refresh token Portal sendiri
});

⚠️ Jebakan yang sering ketemu

TL;DR: Login dengan Google = OAuth 2.0 (otorisasi) + OpenID Connect (identitas): scope openid email profile, dan /token menjawab dengan id_token. Periksa berurutan: tanda tangan (kunci publik Google), iss, aud (harus client_id-mu), exp (detik), sub. Lalu cari akun lewat sub di social_accounts, sambungkan lewat email hanya kalau email_verified true, dan buat akun baru kalau belum ada. Di Laravel: Socialite::driver('google')->stateless()->user(), lalu buat token aplikasimu sendiri.

Yang akan kamu pelajari