> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Panduan Cepat Autentikasi JavaScript

> Hubungkan aplikasi Autentikasi Didit yang aktif ke halaman sign-in yang di-hosting dengan PKCE, validasi callback, pemeriksaan sesi, dan logout.

> [!WARNING]
>
> Autentikasi adalah fitur baru: gunakan contoh alur yang di-hosting ini dengan aplikasi yang Autentikasinya sudah diaktifkan. Paket `@didit-protocol/auth` belum dipublikasikan; API paket di bawah ini adalah pratinjau, bukan panduan mulai cepat yang dapat diinstal.

## Konfigurasi masuk yang di-hosting

Daftarkan URL callback yang tepat dan origin web Anda untuk aplikasi sandbox Anda. Salin origin masuk (`https://<slug>.sandbox.auth.didit.me`) dari konsol, seperti dijelaskan di [ikhtisar](https://docs.didit.me/id/authentication/overview.md). Contoh ini menggunakan API kriptografi browser dan memerlukan HTTPS, atau localhost di sandbox: lihat [pengembangan lokal](https://docs.didit.me/id/authentication/overview.md#pengembangan-lokal) untuk mengetahui apa yang perlu didaftarkan.

Aplikasi Anda yang mengelola `state` dan verifier PKCE. Masuk yang di-hosting mengelola layar kata sandi, email, passkey, telepon, SSO, dan MFA yang wajib. Tidak ada kunci API yang boleh ada dalam kode ini.

```javascript auth.js theme={null}
// Replace both values with your registered application configuration.
const AUTH_BASE = "https://YOUR_SLUG.sandbox.auth.didit.me/";
const REDIRECT_URI = "https://YOUR_APP_ORIGIN/auth/callback";
const PENDING = "didit.auth.pending";
let tokens = null;

function base64url(bytes) {
  return btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

export async function signIn() {
  const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
  const state = base64url(crypto.getRandomValues(new Uint8Array(32)));
  const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier));
  sessionStorage.setItem(PENDING, JSON.stringify({ verifier, state, startedAt: Date.now() }));
  const url = new URL("sign-in", AUTH_BASE);
  url.search = new URLSearchParams({
    redirect_uri: REDIRECT_URI,
    state,
    code_challenge: base64url(new Uint8Array(digest)),
    code_challenge_method: "S256",
  }).toString();
  window.location.assign(url.href);
}

export async function handleCallback() {
  const query = new URLSearchParams(window.location.search);
  const saved = sessionStorage.getItem(PENDING);
  sessionStorage.removeItem(PENDING);
  history.replaceState(null, "", window.location.pathname);
  if (!saved) throw new Error("Start sign-in again.");
  const pending = JSON.parse(saved);
  if (query.get("state") !== pending.state || Date.now() - pending.startedAt > 600000) {
    throw new Error("Invalid or expired sign-in. Start again.");
  }
  if (query.has("error") || !query.get("code")) throw new Error("Sign-in was not completed.");
  const response = await fetch(new URL("token/", AUTH_BASE), {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      grant_type: "authorization_code",
      code: query.get("code"),
      code_verifier: pending.verifier,
      redirect_uri: REDIRECT_URI,
    }),
  });
  if (!response.ok) throw new Error("Code exchange failed. Start sign-in again.");
  tokens = await response.json();
  return getSession();
}

export async function getSession() {
  if (!tokens) return null;
  const response = await fetch(new URL("session/", AUTH_BASE), {
    headers: { Authorization: `Bearer ${tokens.access_token}` },
    cache: "no-store",
  });
  if (!response.ok) {
    tokens = null;
    throw new Error("Session check failed. Sign in again.");
  }
  return response.json();
}

export async function signOut() {
  const current = tokens;
  tokens = null;
  if (!current) return;
  const response = await fetch(new URL("session/", AUTH_BASE), {
    method: "DELETE",
    headers: { Authorization: `Bearer ${current.access_token}` },
  });
  if (response.status !== 204) throw new Error("Local state cleared; server logout failed.");
}
```

Panggil `signIn()` dari tombol masuk Anda. Pada halaman callback yang sudah didaftarkan, panggil `handleCallback()` satu kali, tampilkan status memuat, dan tampilkan errornya jika gagal. Gunakan `getSession()` untuk pengguna saat ini dan `signOut()` untuk keluar. Callback menghapus kodenya dari bilah alamat sebelum membuat permintaan.

Contoh minimal ini menyimpan token di memori dan meminta masuk ulang setelah halaman dimuat ulang atau token akses kedaluwarsa. Untuk sesi yang persisten, gunakan backend Anda dan cookie aman, atau terapkan [rotasi refresh token](https://docs.didit.me/id/authentication/tokens-and-jwks.md) secara serial. Jangan pernah menaruh refresh token di URL atau log. Pemeriksaan sesi di frontend hanya mengatur tampilan; backend Anda harus memvalidasi pemanggil pada setiap permintaan yang dilindungi.

## Pratinjau rilis SDK autentikasi

Inti `@didit-protocol/auth` yang direncanakan menyediakan `createDiditAuth({publishableKey})`, `signIn()`, `handleRedirectCallback()`, `getSession()`, `getToken()`, `onAuthStateChange`, dan `signOut()`, dengan `vendorData` pada identitas. SDK ini dimaksudkan untuk menambahkan sinyal perangkat otomatis dan titik masuk server dengan `verifyToken()`.

Kunci yang dapat dipublikasikan berupa `pk_live_` (aplikasi produksi) atau `pk_test_` (aplikasi sandbox), diikuti encoding base64url tanpa padding dari origin aplikasi Anda.
SDK mengirim panggilan API-nya ke origin tersebut.
Kunci ini bersifat publik: kunci ini mengidentifikasi aplikasi dan bukan rahasia.

### Step-up dan autentikasi ulang dalam pratinjau

* `stepUp({ action, amount?, currency?, redirectUri? })` memanggil endpoint `POST step-up/` pada aplikasi Anda untuk menanyakan apakah `action` memerlukan pemeriksaan identitas.
  `action` berupa `payout`, `bank`, atau `contact`, dan pencairan memerlukan `amount`.
  Ketika salah satu aturan step-up Anda berlaku, SDK mengarahkan ke halaman verifikasi yang dikembalikan Didit.
* `handleStepUpCallback(url?)` dijalankan di halaman tempat orang tersebut kembali.
  Fungsi ini membaca `?step_up=<id>`, menghapusnya dari bilah alamat, dan membaca hasilnya dengan `GET step-up/{id}/`.
* `reauthenticate({ method? })` masuk kembali dengan orang yang sama, di halaman yang di-hosting (`method: "redirect"`, bawaan) atau dengan passkey (`method: "passkey"`, hanya pada domain masuk Didit milik aplikasi Anda).
  Setelah halaman yang di-hosting, selesaikan dengan `handleRedirectCallback()`.
  Jika orang lain yang menyelesaikannya, proses ditolak dengan `step_up_user_mismatch` dan sesi asli tetap berlaku.

Kedua metode step-up menghasilkan `{ id, status, approved, rule, method }`, dengan `status` berupa `not_required`, `pending`, `approved`, `review`, `declined`, atau `expired`.
`redirectUri` menggunakan alamat redirect klien sebagai bawaan dan harus sama persis dengan salah satu alamat redirect aplikasi Anda yang sudah didaftarkan: ketika pemeriksaan diperlukan, Didit menolak alamat lain.
Sebelum backend Anda bertindak berdasarkan step-up, baca kembali step-up dengan `GET step-up/{id}/` dan token akses pengguna, karena hasil yang dilaporkan browser bisa diubah.

Masuk tanpa antarmuka juga dapat mengembalikan `protection_required` ketika aturan proteksi aplikasi Anda menandainya. Pengguna kemudian menyelesaikannya dengan kode yang dikirim Didit ke emailnya (`protection.verify({ code })`) atau dengan passkey (`protection.passkey()`), dan `methods` berisi daftar metode mana dari kedua metode tersebut yang dapat mereka gunakan.

Jangan memasang versi yang hanya diperkirakan atau menulis kode berdasarkan opsi callback yang hanya diperkirakan. Pastikan ekspor paket yang dipublikasikan, penerbit, dan konfigurasi kunci sebelum mengganti contoh yang di-hosting. Kata sandi, kode email, tautan ajaib, passkey, telepon, MFA, masuk melalui media sosial, step-up, dan metode agen akan bergantung pada API yang didukung rilis tersebut.

## Tambahkan produk lain

Backend Anda memverifikasi token akses (lihat [token dan JWKS](https://docs.didit.me/id/authentication/tokens-and-jwks.md)) dan membaca `vendor_data`-nya. Gunakan nilai itu sebagai `vendor_data` saat [membuat sesi verifikasi](https://docs.didit.me/id/sessions-api/create-session.md) atau [membuat token transaksi](https://docs.didit.me/id/transaction-monitoring/sdk-transaction-submission.md). Masuk yang berhasil tidak berarti salah satu produk tersebut telah menyetujui pengguna.

Sebelum rilis, uji pendaftaran, masuk kembali, pembatalan, state yang tidak cocok, kode yang dipakai ulang, lupa kata sandi, MFA, kedaluwarsa, dan keluar pada aplikasi sandbox Anda yang sudah diaktifkan.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.