POST /api/v1/session/delegated
Mint a session acting as an externally-authenticated principal. Guarded.
WARNING: despite the path, this is not a login and it is not open. It is guarded, and
the caller must already hold a certificate-login session belonging to a registered
service permitted for the session:delegated operation. Open, it would let any
unauthenticated caller impersonate any XAuth principal this Gateway's delegator covers.
You do not send the target identity. You send localUser, and the Gateway constructs
the XAuth id by prefixing it with the xauthPrefix configured for your registered
service. A body that tries to name the target itself is refused with
CALLER_SUPPLIED_IDENTITY, because a caller-settable identity would defeat the whole
construction.
Keys created on the resulting session are owned by the target, not by the delegator, which is what keeps per-user grant, revoke and audit intact.
The session inherits the minting service's sender key and is therefore sender-constrained: its holder is the same program holding a second credential, and that program has already proved possession of that key. Binding to the same key closes what would otherwise be the one credential on this surface that a constrained request could mint and an unconstrained one could then spend.
WARNING: the key server's delegation guard is operation-subset only. It has no tenant or namespace scoping, so this Gateway can impersonate any XAuth principal whose operation set its delegator covers. That is a property of the engine, not of this route.
Authentication
Send the session id as Authorization: Bearer <session id>, and an RFC 9449 DPoP proof in the DPoP header if your session is bound to a key. The two are required together, not as alternatives — see Authenticating and Proving you hold your key.
There is no session cookie on any response and none is read on any request. Do not set credentials: "include" on a browser fetch.
Request
| Field | Type | Required | Description |
|---|---|---|---|
localUser | string | yes | Your application's own user id. The Gateway prefixes it to build the XAuth identity; you cannot name that identity directly. |
Example
{
"localUser": "..."
}
Responses
200
A delegated session, acting as the constructed target.
| Field | Type | Required | Description |
|---|---|---|---|
actingAs | string | yes | The XAuth id this session acts as. |
localUser | string | no | |
service | string | no | |
delegator | string | no | The subject of this Gateway's own delegating certificate. |
session | string | yes | The bearer credential. |
ks | KsAddress | yes | |
system | SystemBlock | no | The cached boot snapshot of the key server this Gateway fronts. It carries no credential: the boot call that produces it cannot return one. |
detail | string | yes |
KsAddress
| Field | Type | Required | Description |
|---|---|---|---|
host | string | no | |
port | integer | no |
Example
{
"actingAs": "...",
"localUser": "...",
"service": "...",
"delegator": "...",
"session": "...",
"ks": {
"host": "...",
"port": 0
},
"system": {},
"detail": "..."
}
400
CALLER_SUPPLIED_IDENTITY -- the body named an identity field the caller may not set, or carried subjectToken, which only POST /api/v1/session/scoped takes. Or BAD_REQUEST -- localUser is missing or malformed, or the id the Gateway built from its own configured prefix is not a usable one, which is a fault in this Gateway's configuration rather than in your request.
401
No live session, a DPoP proof that did not verify, or a certificate session whose certificate the key server now refuses.
SESSION_NOT_FOUND -- the credential names no session this Gateway holds.
SESSION_EXPIRED -- it aged out. Both carry reauth: true; obtain a new credential
rather than retrying.
PROOF_* -- the sender constraint refused. See the DPoP section of this document for the
full table; PROOF_MALFORMED is a 400 and PROOF_REPLAY_CACHE_FULL a 503, and the
rest are here.
SCOPED_CREDENTIAL_EXPIRED -- a scoped browser credential passed its fixed lifetime. Use
does not extend it: an idle timeout would be refreshed by exactly the traffic a stolen
handle produces.
CERTIFICATE_REVOKED -- on a session established by certificate login, the key server
re-checks the certificate that session was established with on its operations, and it
is now named by revocation evidence. detail is the key server's sentence. The
Gateway answers this once and then ENDS everything that service holds or minted here --
its sessions, the delegated sessions and the scoped credentials it minted -- so a later
operation on any of them is SESSION_NOT_FOUND. Log in with a different certificate.
SSO_SESSION_EXPIRED -- a single-sign-on session (POST /api/v1/session/oidc) reached
its lifetime, or was idle past its binding's idle bound; it has been ended. Sign in again.
SENDER_KEY_RETIRED -- the session's registered sender key was rotated out and its
overlap has passed (see "The registered service's credential lifecycle"); the session is
closed with this answer. SERVICE_REGISTRATION_ENDED -- the registration a service
credential was issued under was removed or narrowed on this Gateway; it has ended. Both
are final for that credential.
403
NOT_A_SERVICE_SESSION -- the caller's session is not a certificate login.
SERVICE_NOT_REGISTERED -- it is, and no registration matches its principal.
SERVICE_OPERATION_NOT_PERMITTED -- it is registered and this operation is not on
its permitted list.
DELEGATOR_NOT_PERMITTED -- the key server refused this Gateway's own certificate
principal as a delegator: either no client certificate was bound for the connection,
or the enrolled principal does not carry the DELEGATION flag (0x400).
DELEGATOR_TOO_NARROW -- the TARGET holds at least one operation the DELEGATOR does
not. The guard is a superset test with no administrator carve-out, so the fix is to
widen the delegator, never to narrow the check.
TARGET_DISABLED -- the key server refused the delegation because a principal in it
is disabled: the target, or this Gateway's own certificate principal (the key server
names neither; target and delegator are echoed). An administrator enables it;
retrying changes nothing.
404
TARGET_NOT_FOUND -- no XAuth principal with that id exists, so there is nobody to become. This is the lazy-provisioning signal: create the target with POST /api/v1/principals/xauth, which is idempotent, and retry.
500
A fault rather than a refusal.
OP_FAILED is the catch-all: the key server refused in words that match no classified
pattern, so the Gateway cannot say more than that the operation did not happen. Some key
server refusals that are conceptually a caller error arrive here rather than as a 4xx,
because the wire carries no distinguishing code -- where a route can recognise one from
its message it maps it, and each such mapping is documented on the operation.
503
MAJORDOMO_NOT_CONFIGURED or DELEGATION_NOT_CONFIGURED -- this Gateway holds no delegator identity, so it cannot impersonate anybody; nothing was sent to the key server. SERVICE_REGISTRY_NOT_CONFIGURED -- no service registry is loaded. SENDER_BINDING_UNAVAILABLE -- the Gateway is holding its maximum of sender-key bindings and could not record another; the session was not handed out, because a delegated credential this Gateway cannot bind would be spendable by anyone holding it. Retryable. Or CAPACITY_UNAVAILABLE (scope: process, Retry-After) -- this Gateway is at its request ceiling (see "Rate and capacity limits").
413
PAYLOAD_TOO_LARGE (retryable: false) -- the request body is larger than this
deployment accepts. It was refused before it was parsed, and the connection is closed.
Nothing was sent to the key server.
429
RATE_LIMITED (retryable: true, Retry-After) -- the allowance this request is charged
to is spent: the login allowance of its network source (before authentication), or the
allowance, the concurrency ceiling or the live-session ceiling of the identity it was
verified as -- shared by every session that identity holds, including every delegated
and scoped credential a service minted. It carries no scope. Nothing was sent to the
key server; on a login refused after authentication, the session it created has been
closed. See "Rate and capacity limits" above.
Error handling
Every failure answers JSON carrying at least code and detail. Match on code — detail is written for a human debugging the call and its wording is not part of the contract. See the error model.
| Status | Meaning |
|---|---|
400 | CALLER_SUPPLIED_IDENTITY -- the body named an identity field the caller may not set, or carried subjectToken, which only POST /api/v1/session/scoped takes. Or BAD_REQUEST -- localUser is missing or malformed, or the id the Gateway built from its own configured prefix is not a usable one, which is a fault in this Gateway's configuration rather than in your request. |
401 | No live session, a DPoP proof that did not verify, or a certificate session whose certificate the key server now refuses. SESSION_NOT_FOUND -- the credential names no session this Gateway holds. SESSION_EXPIRED -- it aged out. Both carry reauth: true; obtain a new credential rather than retrying. PROOF_* -- the sender constraint refused. See the DPoP section of this document for the full table; PROOF_MALFORMED is a 400 and PROOF_REPLAY_CACHE_FULL a 503, and the rest are here. SCOPED_CREDENTIAL_EXPIRED -- a scoped browser credential passed its fixed lifetime. Use does not extend it: an idle timeout would be refreshed by exactly the traffic a stolen handle produces. CERTIFICATE_REVOKED -- on a session established by certificate login, the key server re-checks the certificate that session was established with on its operations, and it is now named by revocation evidence. detail is the key server's sentence. The Gateway answers this once and then ENDS everything that service holds or minted here -- its sessions, the delegated sessions and the scoped credentials it minted -- so a later operation on any of them is SESSION_NOT_FOUND. Log in with a different certificate. SSO_SESSION_EXPIRED -- a single-sign-on session (POST /api/v1/session/oidc) reached its lifetime, or was idle past its binding's idle bound; it has been ended. Sign in again. SENDER_KEY_RETIRED -- the session's registered sender key was rotated out and its overlap has passed (see "The registered service's credential lifecycle"); the session is closed with this answer. SERVICE_REGISTRATION_ENDED -- the registration a service credential was issued under was removed or narrowed on this Gateway; it has ended. Both are final for that credential. |
403 | NOT_A_SERVICE_SESSION -- the caller's session is not a certificate login. SERVICE_NOT_REGISTERED -- it is, and no registration matches its principal. SERVICE_OPERATION_NOT_PERMITTED -- it is registered and this operation is not on its permitted list. DELEGATOR_NOT_PERMITTED -- the key server refused this Gateway's own certificate principal as a delegator: either no client certificate was bound for the connection, or the enrolled principal does not carry the DELEGATION flag (0x400). DELEGATOR_TOO_NARROW -- the TARGET holds at least one operation the DELEGATOR does not. The guard is a superset test with no administrator carve-out, so the fix is to widen the delegator, never to narrow the check. TARGET_DISABLED -- the key server refused the delegation because a principal in it is disabled: the target, or this Gateway's own certificate principal (the key server names neither; target and delegator are echoed). An administrator enables it; retrying changes nothing. |
404 | TARGET_NOT_FOUND -- no XAuth principal with that id exists, so there is nobody to become. This is the lazy-provisioning signal: create the target with POST /api/v1/principals/xauth, which is idempotent, and retry. |
500 | A fault rather than a refusal. OP_FAILED is the catch-all: the key server refused in words that match no classified pattern, so the Gateway cannot say more than that the operation did not happen. Some key server refusals that are conceptually a caller error arrive here rather than as a 4xx, because the wire carries no distinguishing code -- where a route can recognise one from its message it maps it, and each such mapping is documented on the operation. |
503 | MAJORDOMO_NOT_CONFIGURED or DELEGATION_NOT_CONFIGURED -- this Gateway holds no delegator identity, so it cannot impersonate anybody; nothing was sent to the key server. SERVICE_REGISTRY_NOT_CONFIGURED -- no service registry is loaded. SENDER_BINDING_UNAVAILABLE -- the Gateway is holding its maximum of sender-key bindings and could not record another; the session was not handed out, because a delegated credential this Gateway cannot bind would be spendable by anyone holding it. Retryable. Or CAPACITY_UNAVAILABLE (scope: process, Retry-After) -- this Gateway is at its request ceiling (see "Rate and capacity limits"). |
413 | PAYLOAD_TOO_LARGE (retryable: false) -- the request body is larger than this deployment accepts. It was refused before it was parsed, and the connection is closed. Nothing was sent to the key server. |
429 | RATE_LIMITED (retryable: true, Retry-After) -- the allowance this request is charged to is spent: the login allowance of its network source (before authentication), or the allowance, the concurrency ceiling or the live-session ceiling of the identity it was verified as -- shared by every session that identity holds, including every delegated and scoped credential a service minted. It carries no scope. Nothing was sent to the key server; on a login refused after authentication, the session it created has been closed. See "Rate and capacity limits" above. |