Skip to main content
Examples

Authentication

Authenticate requests to a generated API with an API key (X-API-Key), a JWT bearer token or a client certificate (mTLS) - with examples and the exact error responses.

Every request to a generated API must carry a credential for one of the authentication methods your organization has enabled under Auth & Keys. The API checks the first presented credential accepted by the endpoint, in order (API key, JWT, mTLS); it does not try another credential after a rejection. Send one credential. If no method is enabled, every request is rejected.

An endpoint can narrow this on the dashboard's Endpoints page: Public endpoints need no credential at all, and an endpoint set to ApiKey, Jwt or Mtls accepts only that method (401 for any other credential).

Method Send Best for
API key X-API-Key: <key> header Server-to-server calls, scripts, getting started
JWT bearer Authorization: Bearer <token> header Services that already get tokens from your identity provider (Entra ID, Auth0, Okta …)
mTLS A client certificate in the TLS handshake Machine clients with managed certificates, zero shared secrets

Every example uses these environment variables:

Shell
export RESTWARD_API_URL="https://YOUR-API-HOSTNAME"   # your API's endpoint
export RESTWARD_API_KEY="rw_..."

API key

Send the key in the X-API-Key header. Keys are created per API under Auth & Keys and carry a role: Read Only (GET), Read & Write (GET, POST, PUT) or Admin (all methods, including DELETE).

curl -s "$RESTWARD_API_URL/api/public/artist/1" \
  -H "X-API-Key: $RESTWARD_API_KEY"
const api = process.env.RESTWARD_API_URL;
const headers = { "X-API-Key": process.env.RESTWARD_API_KEY };

const res = await fetch(`${api}/api/public/artist/1`, { headers });
console.log(res.status, await res.json());
import os, requests

api = os.environ["RESTWARD_API_URL"]
session = requests.Session()
session.headers["X-API-Key"] = os.environ["RESTWARD_API_KEY"]

res = session.get(f"{api}/api/public/artist/1")
print(res.status_code, res.json())
using var http = new HttpClient { BaseAddress = new Uri(Environment.GetEnvironmentVariable("RESTWARD_API_URL")!) };
http.DefaultRequestHeaders.Add("X-API-Key", Environment.GetEnvironmentVariable("RESTWARD_API_KEY"));

var res = await http.GetAsync("/api/public/artist/1");
Console.WriteLine($"{(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");
HTTP
HTTP/1.1 200
Content-Type: application/json

{"artist_id":1,"name":"AC/DC"}

A key can also be restricted to IP ranges and has its own per-minute rate limit - see Errors & rate limits.

JWT bearer token

Enable the JWT method and configure the issuer (required), either a JWKS or OpenID discovery URL (tokens signed by your identity provider) or a shared signing key (HMAC), and optionally an audience and a role claim. The API validates the signature, issuer, audience and expiry (30 seconds clock skew), then maps the role claim to Admin, ReadWrite or ReadOnly. Without a role claim, or with an unrecognized value, the configured default scope applies, and that defaults to ReadOnly.

curl -s "$RESTWARD_API_URL/api/public/artist/1" \
  -H "Authorization: Bearer $TOKEN"
const res = await fetch(`${process.env.RESTWARD_API_URL}/api/public/artist/1`, {
  headers: { Authorization: `Bearer ${token}` },
});
res = requests.get(
    f"{api}/api/public/artist/1",
    headers={"Authorization": f"Bearer {token}"},
)
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var res = await http.GetAsync("/api/public/artist/1");

A valid token returns the same 200 as above when its address group has not exceeded the authentication ceiling and a validation slot is available. Otherwise it receives 429 with Retry-After; see Failed authentication and floods. A token scoped ReadOnly cannot write:

HTTP
POST /api/public/artist
Authorization: Bearer $TOKEN

HTTP/1.1 403
{"error":"API key role 'ReadOnly' is not authorized for this operation. Requires 'ReadWrite' or higher."}

mTLS (client certificate)

Enable the mTLS method and tell it which certificates to accept. A certificate is accepted, with the method's default scope (ReadOnly unless configured otherwise), when:

  • its SHA-256 fingerprint is one you listed (pins that exact certificate), or
  • it chains to your trusted CA bundle (PEM) and, if you list subjects (subject DN, CN or a SAN DNS name), its subject is one of them.

Subjects only narrow the CA: anyone can create a self-signed certificate with any subject, so a subject list without a trusted CA is refused when you save it. Blank lines in the lists are ignored. The certificate must also be within its validity period.

Upload the whole chain. RestWard's TLS proxy forwards only your client's own certificate, and the API never downloads issuer certificates, so the CA bundle must contain your root CA and every intermediate CA between it and the client certificates (PEM blocks one after another). An intermediate on its own is not enough: it is not a root, so the chain stays incomplete.

Present the certificate in the TLS handshake. RestWard's TLS proxy forwards it to your API; do not set any certificate header yourself.

curl -s "$RESTWARD_API_URL/api/public/artist/1" \
  --cert client.crt --key client.key
// Node.js: fetch has no client-certificate option; use https with an Agent.
import https from "node:https";
import fs from "node:fs";

const agent = new https.Agent({ cert: fs.readFileSync("client.crt"), key: fs.readFileSync("client.key") });
https.get(`${process.env.RESTWARD_API_URL}/api/public/artist/1`, { agent }, (res) => {
  res.on("data", (chunk) => process.stdout.write(chunk));
});
res = requests.get(
    f"{api}/api/public/artist/1",
    cert=("client.crt", "client.key"),
)
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(X509Certificate2.CreateFromPemFile("client.crt", "client.key"));
using var http = new HttpClient(handler) { BaseAddress = new Uri(Environment.GetEnvironmentVariable("RESTWARD_API_URL")!) };

var res = await http.GetAsync("/api/public/artist/1");

Authentication errors

All error bodies have one field, error.

Situation Status Body
No credential for any enabled method 401 {"error":"Authentication required."}
Unknown API key, or a key of another API 401 {"error":"Invalid API key."}
Revoked API key 401 {"error":"API key has been revoked."}
Expired API key 401 {"error":"API key has expired."}
Invalid, expired or wrongly signed JWT 401 {"error":"Invalid or expired bearer token."}
Certificate matches no mTLS criterion 401 {"error":"Client certificate rejected."}
Request from an IP outside the key's allowed ranges 403 {"error":"IP address not allowed."}
Role too low for the method (e.g. ReadOnly POST) 403 {"error":"API key role 'ReadOnly' is not authorized for this operation. Requires 'ReadWrite' or higher."}
Too many unauthenticated requests from your address 429 {"error":"Too many unauthenticated requests from this address. Try again later."}
The token issuer's signing keys (JWKS) cannot be fetched 503 {"error":"The token issuer's signing keys could not be fetched. Try again later."}

The role message says "API key role" for JWT and mTLS credentials too. A request is checked with one credential only: the first of API key, bearer token and client certificate that it carries (see Failed authentication and floods).

Reconnecting to server...

Please wait while we restore your connection

Connection lost

Retrying in seconds...

Unable to reconnect

The server connection has been lost.
You may need to log in again.

Session Paused

The server has temporarily paused your session.

Session Expired

Your session could not be resumed.
Please reload the page to continue.