Single Sign-On & SAML — Auth

SSO (Single Sign-On) memungkinkan user login sekali dan otomatis terautentikasi di banyak aplikasi. Ini standar di lingkungan enterprise. Konsep utama: IdP…

SSO (Single Sign-On) artinya login sekali di satu tempat, lalu bisa masuk ke banyak aplikasi tanpa memasukkan password lagi. SAML 2.0 adalah salah satu protokol untuk itu, berbasis XML. Bayangin resepsionis gedung perkantoran. Dia memeriksa KTP-mu sekali, lalu memberi surat pengantar bertanda tangan untuk kantor yang mau kamu datangi. Kantor itu gak memeriksa KTP lagi. Dia cukup memeriksa tiga hal di surat: tanda tangan resepsionisnya asli, surat itu memang ditujukan ke kantor ini, dan belum lewat jamnya.

🧪 Tebakan cepat: Pak Andi sudah masuk Portal Sekolah lewat SSO. Lima menit kemudian dia membuka Perpustakaan Digital, yang memakai penyedia login yang sama. Dia diminta password lagi atau gak? Dan Perpustakaan memakai surat yang sama dengan Portal atau gak? Tebak dulu, jawabannya ada di bagian "Aplikasi kedua".

Tiga pihak

Sebelum dipakai, SP dan IdP bertukar metadata sekali: SP memberi tahu entity ID-nya (nama unik SP, https://portal.sekolah.test) dan ACS URL-nya (Assertion Consumer Service, alamat yang menerima assertion: https://portal.sekolah.test/saml/acs). IdP memberi alamat login-nya (https://idp.yayasan.test/sso) dan sertifikat yang dipakai untuk memeriksa tanda tangannya.

Alurnya, langkah demi langkah

Ini alur SP-initiated: dimulai dari aplikasinya. Jam di SAML selalu UTC, jadi 08.00 WIB ditulis 01:00. Persis seperti di Lab:

# Dari, ke Yang terjadi
1 Browser ke Portal GET /rapor tanpa session. Portal membuat AuthnRequest dan menjawab 302 ke https://idp.yayasan.test/sso?SAMLRequest=...&RelayState=%2Frapor
2 Browser ke IdP IdP belum kenal Pak Andi, jadi menampilkan halaman login. Pak Andi memasukkan password (dan MFA). IdP menyimpan session-nya sendiri
3 IdP ke browser IdP membuat assertion yang ditandatangani, lalu mengirim halaman berisi form yang otomatis di-POST ke ACS URL Portal
4 Browser ke Portal POST /saml/acs membawa SAMLResponse. Portal memeriksa assertion-nya. Lolos: Portal membuat session lokal dan menjawab 302 ke /rapor

AuthnRequest-nya kecil. Di URL, XML ini dikompres (DEFLATE) lalu di-base64:

<samlp:AuthnRequest ID="_req7f3a91c2" Version="2.0" IssueInstant="2026-10-09T01:00:00Z"
    Destination="https://idp.yayasan.test/sso"
    AssertionConsumerServiceURL="https://portal.sekolah.test/saml/acs">
  <saml:Issuer>https://portal.sekolah.test</saml:Issuer>
</samlp:AuthnRequest>

Assertion dan yang dicek SP

Ini isi assertion yang tiba di ACS Portal (bagian tanda tangannya dipendekkan):

<saml:Assertion ID="_a91c55e0" IssueInstant="2026-10-09T01:00:12Z">
  <saml:Issuer>https://idp.yayasan.test</saml:Issuer>
  <ds:Signature><!-- RSA-SHA256, sertifikat 4B:1E:9C:07:A2:F3:5D:88 --></ds:Signature>
  <saml:Subject>
    <saml:NameID>[email protected]</saml:NameID>
    <saml:SubjectConfirmationData InResponseTo="_req7f3a91c2"
        Recipient="https://portal.sekolah.test/saml/acs" NotOnOrAfter="2026-10-09T01:05:12Z"/>
  </saml:Subject>
  <saml:Conditions NotBefore="2026-10-09T00:59:42Z" NotOnOrAfter="2026-10-09T01:05:12Z">
    <saml:AudienceRestriction><saml:Audience>https://portal.sekolah.test</saml:Audience></saml:AudienceRestriction>
  </saml:Conditions>
  <saml:AttributeStatement>
    <saml:Attribute Name="role"><saml:AttributeValue>teacher</saml:AttributeValue></saml:Attribute>
    <saml:Attribute Name="department"><saml:AttributeValue>Matematika</saml:AttributeValue></saml:Attribute>
  </saml:AttributeStatement>
</saml:Assertion>

Sebelum percaya satu huruf pun, Portal menjalankan enam cek. Semuanya harus lolos:

Cek Dibandingkan dengan Di assertion ini
Signature sertifikat IdP dari metadata ditandatangani sertifikat 4B:1E:..., cocok
Issuer https://idp.yayasan.test cocok
Audience entity ID Portal, https://portal.sekolah.test cocok
Recipient ACS URL Portal cocok
InResponseTo ID AuthnRequest yang disimpan di session _req7f3a91c2, cocok
NotBefore, NotOnOrAfter jam server Portal saat POST tiba tiba 01:00:13, masih di dalam jendela 5 menit

Lolos semua, jadi NameID ([email protected]) dicocokkan ke user di database Portal, atribut role dan department dibaca, lalu Portal login-kan Pak Andi dengan session-nya sendiri. Satu yang gagal, assertion ditolak dan gak ada session yang dibuat. Lab memperlihatkan tiga penyebab gagal yang biasa ditemui saat memasang SSO: jam server SP yang maju 6 menit, entity ID yang salah ketik di IdP (https://portal.sekolah.test/ dengan garis miring di akhir), dan IdP yang sudah memakai sertifikat baru sementara metadata di SP masih yang lama.

Pemeriksaan tanda tangan XML jangan ditulis sendiri. Pakai library: onelogin/php-saml di PHP (dipakai juga oleh paket SAML untuk Laravel), atau @node-saml/node-saml di Node.

Aplikasi kedua

Lima menit kemudian Pak Andi membuka Perpustakaan Digital. Perpustakaan juga gak punya session, jadi dia juga mengirim AuthnRequest ke IdP. Bedanya di langkah 2: IdP sudah punya session Pak Andi, jadi gak ada halaman login. IdP langsung membuat assertion baru dengan Audience https://perpus.sekolah.test dan mem-POST-nya ke ACS Perpustakaan. Jadi jawaban tebakannya: gak diminta password lagi, dan suratnya beda. Assertion untuk Portal ditolak di Perpustakaan, karena audience-nya bukan Perpustakaan.

Latihan: tiga function

Latihannya memakai object JavaScript sebagai pengganti XML, dengan nama aplikasi https://myapp.com dan IdP https://idp.corp.com/sso:

SAML atau OIDC

OIDC (OpenID Connect) adalah lapisan login di atas OAuth 2.0, protokol yang dipakai "Login dengan Google" di lesson Social Login. Tujuannya sama dengan SAML: IdP membuktikan siapa user-nya ke aplikasi.

SAML 2.0 OIDC
Terbit 2005 2014
Bukti identitas assertion, XML yang ditandatangani ID token, JWT (JSON yang ditandatangani)
Cara sampai ke aplikasi lewat browser: redirect, lalu form POST ke ACS redirect membawa code, lalu server aplikasi menukar code itu langsung ke IdP
Cocok untuk integrasi enterprise dan B2B, terutama sistem lama aplikasi web dan mobile baru

Aturan praktisnya: kalau pelanggan perusahaan meminta "harus bisa login pakai SAML dari IdP kami", sediakan SAML. Kalau kamu membangun dari nol, pilih OIDC: JSON lebih ringan, dan library-nya lebih banyak di web dan mobile.

⚠️ Jebakan yang sering ketemu

TL;DR: SSO: login sekali di IdP, masuk ke banyak SP. Alur SP-initiated: SP mengirim AuthnRequest (menyimpan ID-nya), IdP me-login-kan user, IdP mem-POST assertion XML yang ditandatangani ke ACS URL, lalu SP memeriksa signature, issuer, audience (entity ID-nya sendiri), recipient (ACS URL-nya), InResponseTo, dan jendela waktu NotBefore/NotOnOrAfter sebelum membuat session sendiri. Aplikasi kedua gak minta password lagi karena IdP masih punya session, tapi tetap dapat assertion-nya sendiri. SAML (XML, 2005) untuk enterprise dan sistem lama, OIDC (JWT, di atas OAuth 2.0) untuk aplikasi baru.

Yang akan kamu pelajari