switching clears the token & responses
No token
32

Platform discovery & health (gateway / ops)

Platform

Not user flows — these serve the gateway (token validation) and the orchestrator (liveness/readiness). All return RAW bodies, not the { data } envelope.

  1. GET /.well-known/openid-configuration → the gateway discovers the issuer, JWKS URI, and endpoints
  2. GET /.well-known/jwks.json → the public keys used to validate access tokens
  3. GET /healthz → liveness (the orchestrator restarts the pod if this stops returning 200)
  4. GET /readyz → readiness (DB + Redis; 503 while draining so traffic is held back)
  5. POST /internal/validate → the gateway forward-auths here on a decision-cache miss
GET/.well-known/openid-configurationpublicOIDC discovery metadata

Raw response (not enveloped). The gateway discovers the issuer, JWKS URI, and endpoints.

ℹ︎Field guide — what each value means & where it comes fromno inputs

No request body, path params, query params, or required headers. This is a public OIDC discovery endpoint that needs no authentication (no Authorization header, no x-gateway-context); it returns raw OIDC metadata (issuer, jwks_uri, token_endpoint, supported signing algs).

GET https://api.kerja.team/.well-known/openid-configuration
↩︎Response guide — what comes back & what each value means4 fields

200 OK with a RAW JSON body (NOT wrapped in the { data } envelope); standard OIDC discovery metadata. No notable response headers (public endpoint, no Set-Cookie or no-store).

issuerstringalways
The OIDC issuer identifier URL for this IAM service (e.g. "https://iam.internal"). Clients must match this against the iss claim of issued tokens.
jwks_uristringalways
URL of the JSON Web Key Set endpoint where token-signing public keys are published (e.g. "https://iam.internal/.well-known/jwks.json"). Fetch it to verify access-token signatures.
token_endpointstringalways
URL of the token-issuing endpoint, here the IAM login route (e.g. "https://iam.internal/v1/auth/login"). Clients post credentials here to obtain tokens.
id_token_signing_alg_values_supportedarrayalways
JSON array of JWS signing algorithms supported for token signatures. Use to select the verification algorithm.
  • ES256ECDSA using P-256 and SHA-256 — the only signing algorithm this IAM uses for its tokens.
GET/.well-known/jwks.jsonpublicPublic signing keys (JWKS)

Raw JWKS (the shared issuer's keys — operator access tokens are verified against these too). Honor Cache-Control: key rotation is a two-key overlap so cached keys keep validating across a rotation.

ℹ︎Field guide — what each value means & where it comes fromno inputs

No request body, path params, query params, or required caller headers. This is a public endpoint (no authentication required); it returns the shared issuer's public JWKS signing keys as a raw, unwrapped JSON response used to verify tokens this service issues.

GET https://api.kerja.team/.well-known/jwks.json
↩︎Response guide — what comes back & what each value means8 fields

200 OK with a RAW body (NOT wrapped in the { data } envelope) — a standard JWKS document with a single top-level "keys" array of public signing JWKs used to verify tokens this service's shared issuer signs. No notable Set-Cookie/Cache-Control headers documented.

keys[]arrayalways
Array of JSON Web Keys (public signing keys). A verifier selects the JWK whose kid matches a token header's kid and uses it to check the token signature.
keys[].ktyenumalways
Key type. Identifies the cryptographic key family so the verifier picks the right algorithm parameters.
  • ECElliptic-curve key (the issuer uses EC/ES256 signing keys).
keys[].crvenumalways
Elliptic curve the key lives on; pairs with alg ES256.
  • P-256NIST P-256 curve used for ES256 signatures.
keys[].kidstringalways
Key ID. Match this against the kid in a token's JOSE header to select which JWK verifies that token.
keys[].xstringalways
Base64url-encoded X coordinate of the EC public key point; combined with y to reconstruct the verification key.
keys[].ystringalways
Base64url-encoded Y coordinate of the EC public key point; combined with x to reconstruct the verification key.
keys[].algenumalways
Algorithm the key is used with; the verifier enforces this when validating signatures.
  • ES256ECDSA using P-256 and SHA-256 — the issuer's token signing algorithm.
keys[].useenumalways
Intended public-key use; signals this key is for signature verification, not encryption.
  • sigSignature key — used to verify token signatures.
GET/healthzpublicLiveness probe

Raw { status: ok } while the process is up.

ℹ︎Field guide — what each value means & where it comes fromno inputs

No request body, no path/query params, and no required caller headers. Public liveness probe — no authentication needed; always returns 200 { "status": "ok" } while the process is up.

GET https://api.kerja.team/healthz
↩︎Response guide — what comes back & what each value means1 field

200 OK liveness probe. The body is a RAW JSON object, NOT wrapped in the { data } envelope. Returns { "status": "ok" } whenever the process is up; no notable response headers.

statusenumalways
Liveness indicator for the process. As long as the HTTP server can answer at all it returns 200 with this set to "ok"; the tester can treat a 200 here as the process being alive.
  • okThe process is up and serving; the only value ever returned by this liveness probe (it does not check downstream dependencies).
GET/readyzpublicReadiness probe

Checks DB + Redis. Returns 503 while draining for shutdown or when a dependency is down — a 503 during graceful shutdown is EXPECTED, not a fault.

ℹ︎Field guide — what each value means & where it comes fromno inputs

No request body, path params, query params, or required caller headers. This is a public readiness probe (no Authorization or x-gateway-context needed); it returns 200 {"status":"ok"} when DB and Redis respond within the timeout, or 503 when the service is draining ("shutting_down") or a dependency failed/timed out ("unavailable").

GET https://api.kerja.team/readyz
↩︎Response guide — what comes back & what each value means1 field

200 OK on a healthy service. The body is a RAW JSON object, NOT wrapped in the { data } envelope. On success only one field is returned: { "status": "ok" }. (Failure is 503 with status "shutting_down" or "unavailable" plus a traceId — not part of the success shape.)

statusenumalways
Readiness verdict for the service. On a 200 success this is always "ok", signalling DB and Redis responded within the timeout and the service is not draining. The client/probe treats "ok" as ready-to-serve.
  • okService is ready: DB and Redis healthy within timeout and not shutting down. Only value returned on a 200 success.
POST/internal/validatepublicGateway forward-auth check

Internal (server-to-server) only — never routed through the public gateway in production. On a DECISION-CACHE MISS the gateway forward-auths here for an authoritative live revocation/membership/role check before admitting the request, returning the current { sub, tenant_id, roles, sid }. A warm decision cache lets the gateway admit requests without this hop; it fails closed if IAM is unreachable.

Request body (JSON)
ℹ︎Field guide — what each value means & where it comes from1 field

Internal forward-auth endpoint for the API gateway — no request body, no query/path params. The subject is the bearer access token to be validated (the tester/gateway supply Authorization; you do not type it). Beyond that, the only caller-supplied header is x-internal-key, a shared secret required only when INTERNAL_API_KEY is configured (skipped in local dev).

x-internal-keyheaderstringconditionalout-of-band
Required only when the service is deployed with INTERNAL_API_KEY configured; in local dev the secret is unset and the check is skipped. You must obtain this shared secret from the deployment config/secret store (it must equal INTERNAL_API_KEY) and paste it. It gates this server-to-server-only route; a mismatch returns 403 forbidden.
POST https://api.kerja.team/internal/validate
↩︎Response guide — what comes back & what each value means4 fields

Success is 200 OK returning the { data } envelope with the authoritative live principal { sub, tenant_id, roles, sid }; roles are read from the live membership, not the token claim. Read-only (no audit row, no state change) and always sent with Cache-Control: no-store; no Set-Cookie. The gateway caches a successful result briefly, but 401/403 denials are never cached.

data.subUUIDalways
The validated subject (user) id, taken from the live, re-verified access token. The gateway stamps this into the x-gateway-context it mints as the authoritative principal id.
data.tenant_idUUIDalways
The tenant the session is bound to. Confirmed to still equal the token's tenant_id and the active membership's tenant; the gateway carries it forward as the request's tenant scope.
data.roles[]arrayalways
The user's CURRENT roles read from the live membership (not the possibly-stale token claim) — this is the whole point of the call. The gateway uses these for authorization and stamps them into x-gateway-context. Empty/extra role names are tenant-defined, so there is no fixed enum; common platform values include 'admin'.
data.sidstringalways
The session id confirmed to be active and owned by sub (BOLA guard). Identifies the live session backing this authoritative decision; the gateway propagates it in the context.