Belajar Symfony - Auth Lanjutan: API Tokens & OAuth2
Episode 19 of 27

Belajar Symfony - Auth Lanjutan: API Tokens & OAuth2

Melengkapi autentikasi API modern: JWT access & refresh token, API-Key auth untuk integrasi sederhana, OAuth2 Authorization Code + PKCE untuk SPA, alur penyimpanan & rotasi token, serta konfigurasi firewall untuk tiap mekanisme.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Di episode 12 kita mengenal token sederhana; episode 18 menambahkan header hardening. Episode 19 menyatukan keduanya ke level yang dibutuhkan aplikasi modern: API token yang bisa di-revoke, OAuth2 untuk integrasi pihak ketiga, dan alur auth SPA yang aman tanpa menyimpan secret di browser.

Mengapa ini penting? Karena cara aplikasi diautentikasi menentukan batas amannya. Session cookie tidak cocok untuk mobile/SPA; token statis tidak bisa di-revoke dengan mudah; OAuth2 menuntut standar. Memahami trade-off tiap mekanisme adalah bagian dari menjadi developer backend yang serius.

JWT: Access & Refresh Token

JWT (JSON Web Token) adalah token stateless: klaim (user, role, exp) tertanam di token, diverifikasi dengan tanda tangan — server tidak perlu menyimpan state. Install bundle populer:

Install lexik/jwt
composer require lexik/jwt-authentication-bundle
php bin/console lexik:jwt:generate-keypair

Konfigurasi minimum:

config/packages/lexik_jwt_authentication.yaml
lexik_jwt_authentication:
    secret_key: '%env(resolve:JWT_SECRET_KEY)%'
    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
    pass_phrase: '%env(JWT_PASSPHRASE)%'
    token_ttl: 3600

Firewall memakai pemverifikasi JWT:

Firewall API dengan JWT
security:
    firewalls:
        login:
            pattern: ^/api/login
            stateless: true
            json_login:
                check_path: /api/login
 
        api:
            pattern: ^/api
            stateless: true
            jwt: ~

Alur lengkap:

Login → access token
POST /api/login {"email":"...", "password":"..."}
→ 200 {"token": "<access>", "refresh_token": "<refresh>"}

Token dipakai di header Authorization: Bearer <token>.

Refresh Token

Access token berumur pendek (mis. 1 jam) untuk membatasi dampak jika bocor. Refresh token berumur panjang dipakai untuk mendapatkan access token baru:

Refresh flow
POST /api/token/refresh {"refresh_token": "<refresh>"}
→ 200 {"token": "<access-baru>"}

Refresh token harus di-revoke saat logout dan berputar (rotated) setiap dipakai. Simpan di sisi server (database/Redis) agar bisa dicabut — jangan hanya di tangan klien. Ini topik yang kembali relevan di episode 24 saat memakai Redis untuk shared state.

API-Key Auth: Untuk Integrasi Sederhana

Untuk partner yang butuh akses tanpa login interaktif, API key adalah mekanisme paling sederhana:

Authenticator API key
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
 
final class ApiKeyAuthenticator extends AbstractAuthenticator
{
    public function supports(Request $request): bool
    {
        return $request->headers->has('X-API-KEY');
    }
 
    public function authenticate(Request $request): Passport
    {
        $apiKey = (string) $request->headers->get('X-API-KEY');
 
        return new Passport(
            new UserBadge($apiKey),
            new ApiKeyCredentials($apiKey),
        );
    }
}

Aturan praktis API key:

KunciAlasan
Hash sebelum simpanKey yang bocor di database tidak bisa dipakai
Rotate berkalaBatasi masa hidup key yang kompromi
Scoping per keySetiap partner punya izin berbeda
Jangan via query stringKey bocor ke log & history

API key bukan untuk login pengguna — untuk itu JWT/session. API key adalah "kontrak antar aplikasi".

OAuth2: Integrasi Pihak Ketiga

OAuth2 adalah standar bagaimana aplikasi lain bisa mengakses data user tanpa menerima password. Library standar: league/oauth2-server.

Install league/oauth2-server
composer require league/oauth2-server

Alur Authorization Code (yang paling umum):

100%

Server Symfony perlu endpoint: authorize, token, dan resource. Integrasi penuh melibatkan: client entity, grant types (Authorization Code, Refresh, Client Credentials), dan scope. Untuk SPA yang tidak bisa menyimpan client secret, gunakan PKCE:

PKCE params
code_challenge = BASE64URL(SHA256(verifier))
code_verifier  = string acak 43-128 karakter

Dengan PKCE, SPA mengirim code_challenge saat authorize dan code_verifier saat exchange — sehingga verifier tidak pernah dikirim, dan secret tidak diperlukan. Ini standar untuk SPA modern.

Memilih Mekanisme

MekanismeStatelessRevocableCocok untuk
Session cookieTidakYa (logout server)Web tradisional
JWT accessYaTidak langsungAPI/SPA (umur pendek)
Refresh tokenTidak (tersimpan)YaPendamping JWT
API keyTergantungYa (hash + rotate)Partner/integrasi
OAuth2 + PKCEYaYaLogin pihak ketiga, SPA

Tip

Tidak ada satu mekanisme untuk semua: web admin pakai session, aplikasi internal pakai JWT, partner pakai API key, dan login sosial pakai OAuth2. Aplikasi production yang serius biasanya memakai kombinasi — pisahkan firewall-nya di security.yaml per pattern seperti di episode 12.

Common Pitfalls

  • JWT tanpa revoke — access token tak bisa dicabut sampai kadaluarsa; karena itu TTL-nya pendek + refresh token terpusat.
  • Refresh token tanpa rotasi — token yang sama dipakai berulang; jika bocor, pencuri punya akses selamanya.
  • Secret di client — Authorization Code + PKCE, bukan Client Credentials, untuk SPA.
  • Token di localStorage tanpa proteksi — pastikan XSS terkendali (episode 18); pertimbangkan httpOnly cookie untuk access token di SPA server-rendered.

Penutup

Pada episode 19 ini, kalian telah melengkapi autentikasi API modern.

Inti yang harus dibawa pulang:

  • JWT: access token pendek + refresh token terpusat & di-rotate.
  • API key: hash sebelum simpan, scope per key, rotate berkala.
  • OAuth2 + PKCE: cara SPA mengakses tanpa client secret.
  • Pilih mekanisme sesuai kasus; kombinasi di firewall yang berbeda.
  • Revocability adalah fitur keamanan yang tidak bisa ditawar untuk token jangka panjang.

Di episode 20 selanjutnya kita menahan laju serangan: Rate Limiting & DoS Protection — Symfony RateLimiter, throttling login & API, strategi per-user/per-IP, dan mitigasi DoS di level aplikasi. Sampai jumpa di episode 20!

Belajar Symfony - Auth Lanjutan: API Tokens & OAuth2 | Belajar Symfony