Endpoint uji untuk setiap skema autentikasi API

Basic, Digest, token bearer, API key, tanda tangan HMAC, JWT, OAuth 1.0a, dan OAuth 2.0 dengan PKCE, beserta kredensialnya.

Contoh terakhir dijalankan terhadap API pada

Untuk menguji autentikasi klien API tanpa menyiapkan identity provider, pakai endpoint uji publik di https://api.testingapis.com/api/authmasuk untuk melihat. Ada satu endpoint per skema: HTTP Basic, Digest, token bearer tetap, API key di header, query, atau cookie, dan penandatanganan request HMAC. Login JWT punya refresh token dan token kedaluwarsa untuk tes negatif, server OAuth 2.0 mendukung PKCE dan client credentials, dan server OAuth 1.0a memeriksa request bertanda tangan. Kredensialnya tetap dan publik, tercantum di bawah dan di GET /api/authmasuk untuk melihat. Kredensial yang salah mengembalikan 401 yang benar, dan token valid tanpa role yang tepat mengembalikan 403.

Endpoint dan kredensial

SkemaEndpointKredensial
HTTP BasicGET /api/auth/basicmasuk untuk melihatapibee / password123
HTTP Digest (MD5, qop=auth)GET /api/auth/digestmasuk untuk melihatapibee / password123
Token bearerGET /api/auth/bearermasuk untuk melihatAuthorization: Bearer apibee-token-123
API key, headerGET /api/auth/api-key/headermasuk untuk melihatX-API-Key: apibee-key-123
API key, queryGET /api/auth/api-key/querymasuk untuk melihat?api_key=apibee-key-123
API key, cookieGET /api/auth/api-key/cookiemasuk untuk melihatCookie: api_key=apibee-key-123
Tanda tangan HMAC-SHA256POST /api/auth/hmacmasuk untuk melihatSecret apibee-hmac-secret
Role dan scopeGET /api/auth/roles/adminmasuk untuk melihatadmin-token, user-token, readonly-token
JWTPOST /api/auth/jwt/loginmasuk untuk melihatadmin / admin123, user / user123
OAuth 2.0/api/auth/oauth/*masuk untuk melihatapibee-client / apibee-secret, klien publik apibee-public
OAuth 1.0a/api/auth/oauth1/*masuk untuk melihatConsumer apibee-consumer-key / apibee-consumer-secret, token apibee-access-token / apibee-token-secret

Basic dan Digest

Password yang tidak ada atau salah mengembalikan 401 dengan header WWW-Authenticate, yang membuat browser dan library HTTP meminta kredensial atau mencoba lagi dengan kredensial:

Terminal
$ curl -i -u apibee:password123 https://api.testingapis.com/api/auth/basic
HTTP/1.1 200 OK

{"authenticated":true,"scheme":"basic","user":"apibee"}

$ curl -i https://api.testingapis.com/api/auth/basic
HTTP/1.1 401 Unauthorized
www-authenticate: Basic realm="apibee", charset="UTF-8"

{"status":401,"error":"Unauthorized","message":"Missing or malformed Basic Authorization header."}
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

Digest butuh dua kali bolak-balik. 401 pertama membawa nonce, dan klien menjawab dengan hash password, bukan password itu sendiri. --digest milik curl melakukan keduanya:

Terminal
$ curl -i --digest -u apibee:password123 https://api.testingapis.com/api/auth/digest
HTTP/1.1 401 Unauthorized
www-authenticate: Digest realm="apibee", qop="auth", algorithm=MD5, nonce="MTc5...", opaque="069d..."

HTTP/1.1 200 OK

{"authenticated":true,"scheme":"digest","user":"apibee","qop":"auth","nc":"00000001"}
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

Untuk menguji klien yang harus berurusan dengan server yang menyembunyikan resource terlindungi, /api/auth/basic-hidden/{user}/{pass}masuk untuk melihat mengembalikan 404, bukan 401, saat kredensial tidak cocok.

Token bearer dan API key

Ketiga endpoint API key menerima key yang sama di tempat berbeda, jadi Anda bisa memeriksa apakah klien Anda menaruhnya di tempat yang diharapkan API. Token bearer yang salah mengembalikan WWW-Authenticate: Bearer error="invalid_token".

GET/api/auth/api-key/header
Request ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

401 vs 403

401 berarti server tidak tahu siapa Anda: tanpa kredensial, atau kredensialnya buruk. 403 berarti server tahu persis siapa Anda, dan Anda tidak diizinkan. Klien harus menanganinya secara berbeda. Setelah 401, klien bisa login lagi atau memperbarui token. Setelah 403, login lagi tidak mengubah apa pun. Endpoint role mengembalikan masing-masing:

Terminal
$ curl -i https://api.testingapis.com/api/auth/roles/admin
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer realm="apibee"

$ curl -i -H "Authorization: Bearer user-token" https://api.testingapis.com/api/auth/roles/admin
HTTP/1.1 403 Forbidden

{"status":403,"error":"Forbidden","message":"This endpoint requires the 'admin' role.","roles":["user"],"scopes":["read","write"]}

$ curl -H "Authorization: Bearer admin-token" https://api.testingapis.com/api/auth/roles/admin
{"authorized":true,"user":"Alice Admin","roles":["admin","user"],"scopes":["read","write","delete"]}
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

DELETE /api/auth/roles/resourcemasuk untuk melihat memeriksa scope, bukan role. readonly-token hanya punya read, jadi ia mendapat 403 yang menyebut scope delete yang kurang.

Penandatanganan request HMAC

API pembayaran dan webhook sering menandatangani request alih-alih mengirim secret. Di sini tanda tangannya adalah HMAC-SHA256 dalam hex huruf kecil dari timestamp + "." + raw body, dikirim di X-Signature dengan timestamp di X-Timestamp. Tandatangani byte persis yang Anda kirim. Menyerialisasi ulang JSON setelah menandatangani adalah cara paling umum merusaknya.

JavaScript
import { createHmac } from "node:crypto";

const secret = "apibee-hmac-secret";
const body = JSON.stringify({ orderId: 1001, amount: 49.99 });
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = createHmac("sha256", secret)
  .update(`${timestamp}.${body}`)
  .digest("hex");

const res = await fetch("https://api.testingapis.com/api/auth/hmac", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Timestamp": timestamp,
    "X-Signature": signature,
  },
  body,
});
console.log(res.status, await res.json());
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis
Output
200 { authenticated: true, scheme: 'hmac-sha256', timestamp: 1791341858, bodyLength: 31 }

# The same signature sent with a different body:
401 {
  status: 401,
  error: 'Unauthorized',
  message: 'Signature mismatch.',
  hint: 'X-Signature = lowercase hex HMAC-SHA256(secret, X-Timestamp + "." + raw request body). Optional \'sha256=\' prefix.',
  bodyLength: 30
}

Untuk memeriksa tanda tangan secara manual, generator hash menghitung HMAC-SHA256 di browser.

Login JWT, kedaluwarsa, dan refresh

/api/auth/jwt/loginmasuk untuk melihat mengembalikan access token bertanda tangan yang berlaku 15 menit dan sebuah refresh token. Refresh token berotasi: setiap refresh mengembalikan yang baru, dan yang lama berhenti berfungsi. /api/auth/jwt/expiredmasuk untuk melihat memberikan token yang ditandatangani dengan benar tetapi sudah kedaluwarsa, agar Anda bisa menguji jalur kedaluwarsa tanpa menunggu 15 menit.

JavaScript
const BASE = "https://api.testingapis.com/api/auth/jwt";

const login = await fetch(`${BASE}/login`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ username: "user", password: "user123" }),
});
const tokens = await login.json();
// { accessToken, tokenType: "Bearer", expiresIn: 900, refreshToken, user }

const auth = { Authorization: `Bearer ${tokens.accessToken}` };
console.log((await fetch(`${BASE}/me`, { headers: auth })).status);    // 200
console.log((await fetch(`${BASE}/admin`, { headers: auth })).status); // 403: role is "user"

// A correctly signed token that expired an hour ago, for the negative test.
const { accessToken: expired } = await (await fetch(`${BASE}/expired`)).json();
const old = await fetch(`${BASE}/me`, { headers: { Authorization: `Bearer ${expired}` } });
console.log(old.status, old.headers.get("www-authenticate"));
// 401 Bearer error="invalid_token", error_description="The token expired at '...'"

// Refresh tokens rotate: use the new one next time.
const refreshed = await fetch(`${BASE}/refresh`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ refreshToken: tokens.refreshToken }),
});
console.log(refreshed.status); // 200
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

Tempel token mana pun ke decoder JWT untuk melihat claim dan waktu kedaluwarsanya.

OAuth 2.0 dengan PKCE

Server OAuth mendukung grant authorization code dengan PKCE, client credentials, password, dan refresh token, ditambah introspeksi dan pencabutan. Otorisasi disetujui otomatis sebagai pengguna apibee, jadi seluruh alur bisa dijalankan dalam satu skrip. Redirect URI di localhost atau 127.0.0.1 (port apa pun) dan callback Postman mendapat redirect 302 sungguhan.

Authorization code dengan PKCE

JavaScript
import { createHash, randomBytes } from "node:crypto";

const BASE = "https://api.testingapis.com/api/auth/oauth";
const redirectUri = "http://localhost:3000/callback";

// 1. A random code verifier and its S256 challenge.
const verifier = randomBytes(32).toString("base64url");
const challenge = createHash("sha256").update(verifier).digest("base64url");

// 2. Send the user to /authorize. This server approves at once and redirects
//    to the redirect URI with ?code=...&state=...
const authorize = new URL(`${BASE}/authorize`);
authorize.search = new URLSearchParams({
  response_type: "code",
  client_id: "apibee-public",
  redirect_uri: redirectUri,
  scope: "read profile",
  state: "xyz123",
  code_challenge: challenge,
  code_challenge_method: "S256",
});
const redirect = await fetch(authorize, { redirect: "manual" });
const code = new URL(redirect.headers.get("location")).searchParams.get("code");

// 3. Exchange the code and the verifier for tokens.
const tokenRes = await fetch(`${BASE}/token`, {
  method: "POST",
  body: new URLSearchParams({
    grant_type: "authorization_code",
    client_id: "apibee-public",
    code,
    redirect_uri: redirectUri,
    code_verifier: verifier,
  }),
});
const tokens = await tokenRes.json();

// 4. Call a protected endpoint.
const me = await fetch(`${BASE}/userinfo`, {
  headers: { Authorization: `Bearer ${tokens.access_token}` },
});
console.log(me.status, await me.json());
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis
Output
200 {
  sub: 'apibee',
  name: 'TestingAPIs Tester',
  preferred_username: 'apibee',
  email: null,
  email_verified: null
}

Dua kegagalan yang harus ditangani klien PKCE:

Text
# Sending the same code a second time
400 { error: 'invalid_grant', error_description: 'Authorization code is invalid, expired or already used.' }

# Sending a code_verifier that doesn't match the challenge
400 { error: 'invalid_grant', error_description: 'PKCE verification failed: code_verifier does not match code_challenge.' }

Client credentials

Untuk panggilan antarlayanan, tanpa melibatkan pengguna:

Terminal
$ curl -X POST https://api.testingapis.com/api/auth/oauth/token \
  -d "grant_type=client_credentials&client_id=apibee-client&client_secret=apibee-secret&scope=read"

{"access_token":"oat_3fc4...","token_type":"Bearer","expires_in":3600,"scope":"read"}
Contoh ini memakai endpoint untuk anggota yang sudah masuk.MasukBuat akun gratis

Request bertanda tangan OAuth 1.0a

OAuth 1.0a menandatangani setiap request dengan dua secret, consumer secret dan token secret, alih-alih mengirim token saja. Server uji menerima tanda tangan HMAC-SHA1, HMAC-SHA256, HMAC-SHA512, dan PLAINTEXT. Pakai access token tetap apibee-access-token / apibee-token-secret yang tidak pernah kedaluwarsa, atau jalankan alur three-legged untuk mendapatkan token sendiri. Otorisasi disetujui otomatis sebagai pengguna apibee.

  1. POST /api/auth/oauth1/request_tokenmasuk untuk melihat, ditandatangani hanya dengan consumer key dan secret, dengan oauth_callback diisi URL atau oob.
  2. GET /api/auth/oauth1/authorize?oauth_token=…masuk untuk melihat me-redirect ke callback localhost atau Postman dengan oauth_verifier, dan mengembalikannya sebagai JSON untuk oob.
  3. POST /api/auth/oauth1/access_tokenmasuk untuk melihat, ditandatangani dengan request token dan secret-nya, ditambah oauth_verifier. Access token berlaku satu jam.
The protected resource, with the static access token:
1. New request: GET https://api.testingapis.com/api/auth/oauth1
2. Authorization → Type: OAuth 1.0
     Signature Method:  HMAC-SHA1
     Consumer Key:      apibee-consumer-key
     Consumer Secret:   apibee-consumer-secret
     Access Token:      apibee-access-token
     Token Secret:      apibee-token-secret
     Add authorization data to: Request Headers
3. Send. The response has "authenticated": true.

The three-legged flow, with the same Authorization settings:
1. POST https://api.testingapis.com/api/auth/oauth1/request_token
   Leave Access Token and Token Secret empty.
   Advanced → Callback URL: oob
2. Open GET https://api.testingapis.com/api/auth/oauth1/authorize?oauth_token=<oauth_token from step 1>
   and copy oauth_verifier from the JSON.
3. POST https://api.testingapis.com/api/auth/oauth1/access_token
     Access Token:  oauth_token from step 1
     Token Secret:  oauth_token_secret from step 1
     Advanced → Verifier: oauth_verifier from step 2
4. Use the oauth_token and oauth_token_secret it returns as
   Access Token and Token Secret for GET /api/auth/oauth1.

PLAINTEXT, di tab cURL, tidak butuh library penandatanganan: tanda tangannya adalah signing key itu sendiri, consumer_secret&token_secret, dengan & dikirim sebagai %26. Pakai untuk memeriksa kredensial, lalu beralih ke HMAC-SHA1 untuk menguji kode penandatanganan Anda.

Saat tanda tangan tidak cocok, 401 menyertakan signature base string yang dibangun server, sehingga Anda bisa membandingkannya dengan milik klien Anda. Kegagalan yang layak diuji:

Text
# Signed with the wrong token secret
401 signature_invalid: Signature mismatch.
details.signatureBaseString: GET&https%3A%2F%2Fapi.testingapis.com%2Fapi%2Fauth%2Foauth1&oauth_consumer_key%3D...

# The same oauth_nonce sent twice
401 nonce_used: This oauth_nonce was already used with this timestamp. Send a new nonce.

# The same request token exchanged twice
401 token_used: This request token was already exchanged for an access token.

Aturan tanda tangan OAuth 1.0a membahas di mana parameter diletakkan, jendela timestamp, dan setiap kode oauth_problem.

Tes negatif yang layak ditulis

  • Tanpa kredensial: harapkan 401 dan header WWW-Authenticate.
  • Password salah, key salah, token diubah: 401, tidak pernah 500.
  • Pengguna valid tanpa role atau scope: 403, dan klien tidak me-logout pengguna.
  • JWT kedaluwarsa: klien melakukan refresh sekali, lalu mengulang request aslinya.
  • Refresh token dipakai dua kali: pemakaian kedua gagal.
  • Kode OAuth dipakai dua kali, atau dengan verifier yang salah: invalid_grant.
  • Tanda tangan HMAC atas body yang berbeda: 401.
  • Request OAuth 1.0a dengan nonce yang dipakai ulang atau tanda tangan salah: 401 nonce_used atau signature_invalid.

Konsep di balik tes-tes ini ada di pelajaran autentikasi dan otorisasi (dalam bahasa Inggris).