Autentikasi
Semua API IDCloud (kontrak Web & SDK dan API) menggunakan OAuth2 dengan JWT Bearer Grant Type (RFC 7523). Anda membuat JWT assertion berumur pendek di back-end, menukarnya dengan Bearer token, dan menggunakan token tersebut di setiap panggilan berikutnya.
JWT assertion harus dibuat di back-end saja. Jangan pernah mengekspos private key Anda di kode front-end, aplikasi mobile, repositori, atau log.
Mendapatkan kredensial
Sebelum dapat membuat token, Anda memerlukan service account yang disediakan oleh Unico. Hubungi dukungan Unico dan berikan:
- Nama service account (maks. 12 karakter)
- Nama, email, dan nomor telepon penanggung jawab (hanya nomor Brasil, AS, atau Meksiko)
Anda akan menerima:
- Nama akun unik
- Tenant ID
- Base JWT payload
- File private key (format
.pem)
Pertahankan service account yang terpisah untuk UAT dan Production.
Membangun JWT assertion
Assertion adalah JWT dalam format JWS kompak: {Base64url(Header)}.{Base64url(Payload)}.{Base64url(Signature)}.
{
"alg": "RS256",
"typ": "JWT"
}
| Claim | Nilai | Catatan |
|---|---|---|
iss | <account_name>@<tenant_id>.iam.acesso.io | Diberikan bersama kredensial Anda |
aud | https://identityhomolog.acesso.io (UAT) atau https://identity.acesso.io (Production) | Harus sesuai dengan host token endpoint |
scope | * | Memberikan semua izin |
iat | Unix timestamp (detik) | Waktu JWT diterbitkan |
exp | iat + maks. 3600 | Tidak boleh melebihi 1 jam dari iat |
{
"aud": "https://identity.acesso.io",
"scope": "*",
"iat": 1738086000,
"exp": 1738089600
}
Tandatangani header + payload menggunakan RS256 (RSA + SHA-256) dengan private key .pem yang diberikan oleh Unico.
Field apa pun yang tidak tercantum di atas (misalnya sub, jti, nbf) akan menyebabkan error 1.2.22. Gunakan hanya klaim yang ditampilkan.
Meminta token
Token endpoint sama untuk kedua kontrak:
| Environment | Endpoint |
|---|---|
| Production | POST https://identity.acesso.io/oauth2/token |
| UAT | POST https://identityhomolog.acesso.io/oauth2/token |
| Parameter | Nilai |
|---|---|
Content-Type | application/x-www-form-urlencoded |
grant_type | urn:ietf:params:oauth:grant-type:jwt-bearer |
assertion | JWT yang telah ditandatangani |
- cURL
- Node.js
- Python
curl -X POST https://identity.acesso.io/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
-d "assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
import jwt from 'jsonwebtoken';
import fs from 'fs';
import qs from 'querystring';
const privateKey = fs.readFileSync('./private-key.pem');
const now = Math.floor(Date.now() / 1000);
const assertion = jwt.sign(
{
aud: 'https://identity.acesso.io',
scope: '*',
iat: now,
exp: now + 3600,
},
privateKey,
{ algorithm: 'RS256' }
);
const res = await fetch('https://identity.acesso.io/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: qs.stringify({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion,
}),
});
const { access_token, expires_in } = await res.json();
import time
import jwt # PyJWT
import requests
with open("private-key.pem", "rb") as f:
private_key = f.read()
now = int(time.time())
assertion = jwt.encode(
{
"aud": "https://identity.acesso.io",
"scope": "*",
"iat": now,
"exp": now + 3600,
},
private_key,
algorithm="RS256",
)
response = requests.post(
"https://identity.acesso.io/oauth2/token",
data={
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": assertion,
},
)
token_data = response.json()
access_token = token_data["access_token"]
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
| Field | Tipe | Deskripsi |
|---|---|---|
access_token | string | JWT access token. Gunakan di Authorization: Bearer <token> pada semua panggilan API. |
expires_in | integer | Waktu kedaluwarsa dalam detik. Contoh: 3600. |
token_type | string | Selalu Bearer. |
Menggunakan token
Tambahkan token ke header Authorization di setiap permintaan API. Header-nya identik untuk kedua kontrak — yang berbeda adalah host dan path dari API yang Anda panggil:
| Kontrak | Production host | UAT host |
|---|---|---|
| Web & SDK | https://api.idcloud.unico.app | https://api.idcloud.uat.unico.app |
| API | https://api.id.unico.app | https://api.id.uat.unico.app |
Web & SDK — Authorization adalah satu-satunya header autentikasi yang diperlukan:
curl -X POST https://api.idcloud.unico.app/client/v1/process \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
API — Authorization digunakan bersama header APIKEY:
curl -X POST https://api.id.unico.app/processes/v1 \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "APIKEY: $API_KEY" \
-H "Content-Type: application/json" \
-d '{ ... }'
Pembaruan token
Token kedaluwarsa setelah 3600 detik. Terapkan pembaruan proaktif di back-end Anda:
- Pantau
expires_indari respons token dan simpan timestamp kedaluwarsa. - Minta token baru ketika tersisa 10 menit atau kurang sebelum kedaluwarsa.
- Jangan pernah menunggu
401di production untuk memicu pembaruan.
Referensi API
Spesifikasi OpenAPI lengkap untuk token endpoint tersedia di authentication.yaml.
| Metode | Path | Deskripsi |
|---|---|---|
POST | /oauth2/token | Tukarkan JWT assertion yang ditandatangani dengan Bearer access token |
Kode error
| Kode | Deskripsi | Tindakan |
|---|---|---|
1.0.1 | ID yang diberikan dalam pembentukan iss salah | Verifikasi field iss sesuai dengan tenant ID yang diberikan saat private key dibuat |
1.0.14 | Aplikasi tidak aktif | Tanyakan ke project manager apakah aplikasi yang digunakan sudah aktif |
1.1.1 | Parameter scope tidak diberikan | Tambahkan "scope": "*" ke JWT payload Anda |
1.2.4 | JWT assertion tidak valid | JWT assertion tidak lagi valid. Dua kemungkinan penyebab: (a) waktu saat ini sudah melewati exp (JWT benar-benar kedaluwarsa — buat assertion baru untuk setiap permintaan token); atau (b) exp melebihi iat + 3600 (durasi terlalu panjang — batasi exp pada iat + 3600). |
1.2.5 | Validasi JWT gagal | JWT tidak dapat divalidasi. Verifikasi parameter dan pastikan ditandatangani dengan RS256 dan private key yang benar |
1.2.6 | Private key tidak lagi valid | Private key yang digunakan untuk menandatangani JWT tidak lagi diterima. Minta kredensial baru untuk akun tersebut |
1.2.7 | JWT sudah digunakan | JWT tidak lagi diterima karena sudah digunakan. Buat assertion baru untuk setiap permintaan token |
1.2.11 | Akun tidak aktif | Akun yang digunakan tidak aktif |
1.2.14 | Akun tidak memiliki izin yang diperlukan | Akun yang digunakan tidak memiliki izin yang diperlukan |
1.2.18 | Akun dikunci sementara | Akun telah dikunci sementara karena melebihi jumlah percobaan autentikasi yang tidak valid |
1.2.19 | Peniruan identitas pengguna tidak diizinkan | JWT berisi klaim sub yang mengarah ke akun yang tidak diizinkan untuk peniruan identitas. Hapus klaim sub dari payload. |
1.2.20 | Dekoding JWT gagal | Gagal mendekode JWT. Verifikasi format token dan pastikan ditandatangani dengan RS256. |
1.2.21 | Private key salah / Autentikasi gagal | Tanda tangan JWT tidak dapat diverifikasi terhadap kunci mana pun yang dikenal untuk akun ini. Pastikan Anda menggunakan file private key .pem yang benar untuk service account dan environment ini. |
1.2.22 | Field yang tidak diizinkan dalam payload | JWT berisi field payload ekstra yang tidak diizinkan. Hapus klaim apa pun yang tidak tercantum dalam panduan ini (misalnya sub, jti, nbf). Catatan: jika Anda menyertakan klaim sub dan menerima error 1.2.19, error tersebut yang berlaku. |
1.3.1 | Pembatasan akses IP | IP Anda tidak ada dalam daftar yang diizinkan untuk akun ini |
1.3.2 | Pembatasan akses berbasis waktu | Permintaan berada di luar jendela waktu yang diizinkan untuk akun ini |
Langkah berikutnya
- Environments — host sandbox vs production
- Web & SDK — Create Process — panggilan pertama setelah autentikasi
- API — Create Process — panggilan pertama setelah autentikasi