Dokumentasi Developer
PAVLO API & Integrasi
Integrasi aplikasi pihak ketiga dengan PAVLO. Fitur premium — aktif untuk tenant dengan paket yang menyertakan API Access / SSO.
https://api.pavlo.idAplikasi: https://app.pavlo.idDua mekanisme integrasi
| API Key (M2M) | OIDC SSO | |
|---|---|---|
| Untuk | Server-to-server: baca data, validasi kredensial | "Login with PAVLO" — user login pakai akun PAVLO |
| Auth | API key statis (pavlo_live_…) | OAuth2 / OpenID Connect (redirect) |
| Password user | App Anda mengirim email+password user | User login langsung di PAVLO (app tak pegang password) |
| Fitur plan | api_access | sso |
Rekomendasi: untuk login user pihak ketiga gunakan OIDC — user tak menyerahkan password ke aplikasi Anda. API Key cocok untuk integrasi data server-to-server & validasi kredensial terkontrol.
A. API Key (M2M)
A.1 Membuat API Key
Admin tenant → Settings › API & Integrasi › Buat API Key. Pilih scope + (opsional) kedaluwarsa. Secret penuh (pavlo_live_…) ditampilkan sekali — simpan dengan aman.
auth:validate— validasi login user / ESS / klienread:employees— baca daftar karyawanread:payslips,read:clients— disiapkan untuk endpoint berikutnya
A.2 Autentikasi
Authorization: Bearer pavlo_live_xxxxxxxx...
# atau
X-API-Key: pavlo_live_xxxxxxxx...Rate limit 600 request/menit per key. Key terikat ke satu tenant — semua data & validasi otomatis ter-scope.
A.3 Endpoint — https://api.pavlo.id/api/external/v1
Validasi kredensial (scope auth:validate)
POST /api/external/v1/auth/validate/user # user admin/staff tenant
POST /api/external/v1/auth/validate/ess # karyawan ESS (tenant = key)
POST /api/external/v1/auth/validate/client # PIC klien
Body: { "email": "...", "password": "..." }Response 200:
{
"success": true,
"data": {
"valid": true,
"identity": { "id":"...", "email":"...", "name":"...", "tenant_id":"...", "role":"admin" },
"token": { "access_token":"<JWT>", "token_type":"Bearer", "expires_in":300 }
}
}Kredensial salah → 401. Identitas lintas-tenant ditolak (terikat ke tenant key).
Baca data (scope read:employees)
GET /api/external/v1/employees?q=&status=&page=1&per_page=50A.4 Keamanan
- Secret di-hash SHA-256 (tak pernah disimpan plaintext).
- Rotate / cabut kapan saja dari Settings. Setiap panggilan di-audit.
- ⚠️
auth:validateberarti app Anda memegang password user — untuk login user pihak ketiga gunakan OIDC.
B. OIDC SSO — “Login with PAVLO”
PAVLO bertindak sebagai OpenID Provider. Aplikasi Anda (Relying Party) mendelegasikan login via OAuth2 Authorization Code + PKCE.
- Issuer:
https://api.pavlo.id - Discovery:
GET /.well-known/openid-configuration - JWKS:
GET /oauth/jwks— token RS256, verifikasi tanpa secret - Grant
authorization_code+ PKCE S256 (wajib), public client (tanpa secret) - Scopes:
openidprofileemail· subjek (MVP): user admin/staff tenant
B.1 Registrasi Aplikasi
Admin tenant → Settings › API & Integrasi › SSO › Daftar Aplikasi. Isi nama + Redirect URI (wajib https://, atau http://localhost untuk dev). Anda dapat client_id (pavlo_client_…).
B.2 Endpoint OIDC
https://api.pavlo.id/.well-known/openid-configuration | GET | Discovery document |
https://api.pavlo.id/oauth/jwks | GET | Public keys (verifikasi token) |
https://app.pavlo.id/oauth/authorize | GET (browser) | Halaman login + consent |
https://api.pavlo.id/oauth/token | POST (form) | Tukar code → token |
https://api.pavlo.id/oauth/userinfo | GET (Bearer) | Klaim profil user |
Endpoint authorization ada di host aplikasi; sisanya di host API. Library OIDC standar membaca ini otomatis dari discovery — cukup arahkan ke issuer https://api.pavlo.id.
B.3 Klaim id_token & rotasi key
iss, sub, aud, exp, iat, nonce, email, name, tenant_id. Token berlaku 1 jam; authorization code single-use 60 detik.
PAVLO mendukung rotasi key multi-kid. RP wajib mencocokkan kid header token ke key di JWKS & re-fetch JWKS berkala (jangan hardcode satu key) — library OIDC standar menangani ini otomatis.
Guide Integrasi
Guide 1 — Validasi login via API Key (M2M)
curl -X POST https://api.pavlo.id/api/external/v1/auth/validate/ess \
-H "Authorization: Bearer pavlo_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"email":"karyawan@perusahaan.com","password":"rahasia"}'
# → 200 { valid:true, identity:{...}, token:{ access_token, expires_in:300 } }
# → 401 jika kredensial salahGuide 2a — OIDC dengan library standar (rekomendasi)
Arahkan client OIDC ke issuer https://api.pavlo.id. Contoh openid-client (Node.js):
import { Issuer, generators } from 'openid-client'
const pavlo = await Issuer.discover('https://api.pavlo.id')
const client = new pavlo.Client({
client_id: 'pavlo_client_xxx',
redirect_uris: ['https://app-anda.com/callback'],
response_types: ['code'],
token_endpoint_auth_method: 'none', // public client (PKCE)
})
// Mulai login:
const code_verifier = generators.codeVerifier()
const code_challenge = generators.codeChallenge(code_verifier)
const authUrl = client.authorizationUrl({
scope: 'openid profile email',
code_challenge, code_challenge_method: 'S256', state, nonce,
})
// simpan code_verifier+state, redirect user ke authUrl
// Di /callback:
const params = client.callbackParams(req)
const tokenSet = await client.callback(redirectUri, params, { code_verifier, state, nonce })
const claims = tokenSet.claims() // { sub, email, name, tenant_id } — terverifikasi vs JWKSPassport, Spring Security, dll. tinggal diarahkan ke issuer yang sama.
Guide 2b — NextAuth / Auth.js v5 (Next.js)
Tambahkan PAVLO sebagai custom OIDC provider. Auto-discovery dari issuer; PKCE + public client.
// auth.ts
import NextAuth from "next-auth"
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
{
id: "pavlo",
name: "PAVLO",
type: "oidc",
issuer: "https://api.pavlo.id", // auto-discovery
clientId: process.env.PAVLO_CLIENT_ID, // pavlo_client_xxx
client: { token_endpoint_auth_method: "none" }, // public client (PKCE, tanpa secret)
checks: ["pkce", "state", "nonce"],
authorization: { params: { scope: "openid profile email" } },
profile(p) {
return { id: p.sub, name: p.name, email: p.email }
},
},
],
})
// app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth"Redirect URI yang didaftarkan di PAVLO: https://app-anda.com/api/auth/callback/pavlo (pola callback NextAuth: {NEXTAUTH_URL}/api/auth/callback/{providerId}). Trigger login via signIn("pavlo").
Guide 2c — OIDC manual (PKCE, tanpa library)
# 1. Generate PKCE (S256)
code_verifier=$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')
code_challenge=$(printf %s "$code_verifier" | openssl dgst -binary -sha256 \
| openssl base64 | tr '+/' '-_' | tr -d '=')
# 2. Redirect browser ke authorization endpoint:
# https://app.pavlo.id/oauth/authorize?response_type=code
# &client_id=pavlo_client_xxx&redirect_uri=https://app-anda.com/callback
# &scope=openid%20profile%20email&state=<acak>
# &code_challenge=$code_challenge&code_challenge_method=S256&nonce=<acak>
# → user login+setuju → balik ke https://app-anda.com/callback?code=<CODE>&state=<acak>
# 3. Tukar code → token (server-to-server, form-encoded)
curl -X POST https://api.pavlo.id/oauth/token \
-d grant_type=authorization_code -d code=<CODE> \
-d code_verifier=$code_verifier -d client_id=pavlo_client_xxx \
-d redirect_uri=https://app-anda.com/callback
# → { id_token, access_token, token_type:"Bearer", expires_in:3600, scope }
# 4. (opsional) profil
curl https://api.pavlo.id/oauth/userinfo -H "Authorization: Bearer <access_token>"kid) · iss = https://api.pavlo.id · aud = client_id Anda ·exp belum lewat · nonce cocok.Referensi Error
API eksternal (/api/external/v1/*)
401— API key tidak valid / dicabut / kedaluwarsa, atau kredensial salah403— fiturapi_accesstak ada di plan, atau key tak punya scope429— rate limit per-key terlampaui (600/menit)
OIDC token endpoint (/oauth/token)
Format { "error": "...", "error_description": "..." }:
invalid_grant— code salah/kedaluwarsa/terpakai, PKCE tak cocok, redirect_uri/client_id bedaoidc_not_configured(503) — OIDC belum diaktifkan
Semua endpoint memerlukan tenant dengan paket premium yang sesuai (api_access / sso). Butuh akses? Hubungi admin tenant Anda atau tim PAVLO.