mikakimikaki.org

mikaki API reference — OIDC and session checks

This reference covers registered server-side Web clients using ES256 private_key_jwt, Code and S256 PKCE. Native public clients, FAPI and Vault APIs have separate contracts. Follow the integration guide for sequencing and the local RP example for executable code.

Endpoint index#

The issuer is https://auth.mikaki.org. Fetch standard endpoints from Discovery and require an exact issuer match. These are the public values checked on October 3, 2026.

Method and pathPurpose and authentication
GET /.well-known/openid-configurationPublic metadata; no authentication
GET /jwksPublic signing keys; no authentication
GET /authorizeBrowser authorization; registered client and PKCE
POST /tokenBackend code exchange; client assertion
GET / POST /userinfoSubject lookup; Access Token
GET / POST /logoutOP logout with user confirmation
POST /session/checkCustom session check; a new client assertion

Keep private keys, codes, tokens and assertions on the application server and out of URLs and diagnostic logs. Do not distribute server-client private keys to a browser-only SPA.

GET /authorize#

Navigate the browser to the authorization endpoint with URL-encoded values.

ParameterValue or source
client_idRegistered client ID
redirect_uriExact registered HTTPS callback
response_type / scopecode / openid for the minimal profile
stateRandom value bound to this browser and an unconsumed transaction
nonceFresh random value for ID Token validation
code_challengeSHA-256 of the verifier, base64url without trailing =
code_challenge_methodS256

Success returns query parameters code, state and iss to the registered callback. Validate state and the pinned issuer before exchanging the code. Handle error responses without creating a session. Invalid destinations may be rejected on the OP page rather than redirected. Never use fixed state, nonce or verifier values.

POST /token#

Send Content-Type: application/x-www-form-urlencoded from the backend.

FieldValue
grant_typeauthorization_code
codeUnused code from this callback
redirect_uriMatching registration and authorization request
code_verifierSaved verifier from this transaction
client_idRegistered client ID
client_assertion_typeurn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertionES256 JWT described below

The JWT header uses alg=ES256 and the kid of the registered public key. Both iss and sub are the client ID; aud is the exact token endpoint URL from Discovery. Generate a new jti and short iat/exp within operational limits for each request.

Successful JSON includes access_token, token_type, expires_in and id_token. In the normal Bearer profile the Access Token is opaque, not a JWT; expires_in is seconds. This public profile has no refresh-token grant.

Validate ID Token signatures with the issuer JWKS and allowed algorithms, then issuer, audience, times, nonce and required auth_time. Identify users by the issuer/pairwise-subject pair. Decoding a JWT is not validation.

Common errors use JSON error. These are current implementation mappings, not an exhaustive catalog for every path.

HTTP / errorAction
400 invalid_requestCheck required fields and format
401 invalid_clientCheck registered key, kid, aud, signature and time limits
400 invalid_grantCheck code, PKCE, redirect and replay; start a fresh login
400 unsupported_grant_typeUse the supported grant
500 server_errorServer failure; do not create a session

After a timeout or lost response, do not resend the code or assertion. Start a fresh login.

GET / POST /userinfo#

For the normal profile use Authorization: Bearer <access_token>. POST also uses this header, rather than moving the token into a URL or form. DPoP-bound tokens require the corresponding proof and authentication scheme.

The minimal success response is {"sub":"<pairwise-subject>"}. Require it to match the validated ID Token subject. The profile scope does not promise a name or email, and ordinary login does not return Vault notes.

Invalid, expired or revoked tokens return 401 with a Bearer or DPoP challenge. The implementation contract returns internal failures as 503 with Retry-After: 5 and no-store, without a token challenge or stale claims. Do not interpret 503 as consent withdrawal. UserInfo does not replace RP session validation or authorize general application APIs.

POST /session/check#

This is a mikaki extension. Send Content-Type: application/json with the following shape. Angle-bracket values are explanatory placeholders, not a usable request.

{
  "client_id": "<registered-client-id>",
  "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
  "client_assertion": "<new-signed-es256-jwt>",
  "sid": "<validated-id-token-sid>"
}

Set assertion aud to https://auth.mikaki.org/session/check. A token-endpoint assertion cannot be reused. Use a fresh jti and do not send the user's SSO cookie or an Access Token.

An active session returns active=true, sub, auth_time, expires_at, lease_ttl, app_idle_timeout, policy_revision and session_policy_revision. Times are Unix seconds; TTL and idle timeout are seconds. Match sub and auth_time against the ID Token. Cap validity at parent SSO expires_at and measure lease_ttl from the start of the check. Use returned values rather than hardcoding five minutes.

Unknown, other-client, unissued or revoked sid values return 200 with {"active":false}. This is not a successful login. Malformed requests return 400; rejected client authentication returns 401. Those rejection paths do not promise a JSON error body. Responses are no-store.

A failed initial check cannot create a new RP session. During an OP outage an existing session is usable only until its current lease expires, without extension. Delayed responses or callbacks must not undo revocation.

GET / POST /logout and Back-Channel delivery#

Use the Discovery end_session_endpoint. Supply id_token_hint, a registered post_logout_redirect_uri, and return state as appropriate; not all are mandatory for every request. Invalid hints or destinations cannot authorize arbitrary redirects. POST uses form fields and proceeds through confirmation.

Clearing an RP cookie differs from ending OP SSO. When an RP registers a Back-Channel receiver, the OP sends form field logout_token to that RP endpoint. Validate its signature, pinned issuer, your client audience, times, events and sid; reject nonce and revoke the corresponding sessions. Handle duplicates and callbacks that arrive after revocation.

Do not depend on browser-return/notification arrival order. Continue enforcing session-check leases. The logout test evidence does not guarantee notification delivery to every production RP.

Detailed contracts and changes#

This reference follows the RP contract, session/check, UserInfo and current token error implementation. Consult OIDC Core for the standard. During this experimental phase, check current public Discovery, the target commit and operational configuration when integrating.