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.

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 (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:
composer require lexik/jwt-authentication-bundle
php bin/console lexik:jwt:generate-keypairKonfigurasi minimum:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 3600Firewall memakai pemverifikasi JWT:
security:
firewalls:
login:
pattern: ^/api/login
stateless: true
json_login:
check_path: /api/login
api:
pattern: ^/api
stateless: true
jwt: ~Alur lengkap:
POST /api/login {"email":"...", "password":"..."}
→ 200 {"token": "<access>", "refresh_token": "<refresh>"}Token dipakai di header Authorization: Bearer <token>.
Access token berumur pendek (mis. 1 jam) untuk membatasi dampak jika bocor. Refresh token berumur panjang dipakai untuk mendapatkan access token baru:
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.
Untuk partner yang butuh akses tanpa login interaktif, API key adalah mekanisme paling sederhana:
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:
| Kunci | Alasan |
|---|---|
| Hash sebelum simpan | Key yang bocor di database tidak bisa dipakai |
| Rotate berkala | Batasi masa hidup key yang kompromi |
| Scoping per key | Setiap partner punya izin berbeda |
| Jangan via query string | Key bocor ke log & history |
API key bukan untuk login pengguna — untuk itu JWT/session. API key adalah "kontrak antar aplikasi".
OAuth2 adalah standar bagaimana aplikasi lain bisa mengakses data user tanpa menerima password. Library standar: league/oauth2-server.
composer require league/oauth2-serverAlur Authorization Code (yang paling umum):
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:
code_challenge = BASE64URL(SHA256(verifier))
code_verifier = string acak 43-128 karakterDengan 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.
| Mekanisme | Stateless | Revocable | Cocok untuk |
|---|---|---|---|
| Session cookie | Tidak | Ya (logout server) | Web tradisional |
| JWT access | Ya | Tidak langsung | API/SPA (umur pendek) |
| Refresh token | Tidak (tersimpan) | Ya | Pendamping JWT |
| API key | Tergantung | Ya (hash + rotate) | Partner/integrasi |
| OAuth2 + PKCE | Ya | Ya | Login 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.
Pada episode 19 ini, kalian telah melengkapi autentikasi API modern.
Inti yang harus dibawa pulang:
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!