Skip to content

Exchange an Ed25519 public-key assertion for application tokens.

POST
/direct-issue/public-key
curl --request POST \
--url https://native-api.sudomimus.com/direct-issue/public-key \
--header 'Authorization: <Authorization>' \
--header 'Content-Type: application/json' \
--data '{ "applicationAnchor": "example" }'

Authenticates an Account or one of its Agent/Automation principals with a compact JWT signed by a registered Ed25519 key. The credential’s immutable Application/Sector applicability must include the named application. Account credentials issue ordinary application access tokens; Workload credentials issue the dedicated Workload access-token type with pairwise act.sub. Credential rejection uses the single opaque reason PublicKeyDirectDenied. After signature and replay verification, Layer 1 requires PUBLIC_KEY_DIRECT (Account), AGENT_PUBLIC_KEY_DIRECT (Agent), or AUTOMATION_PUBLIC_KEY_DIRECT (Automation), selected from the credential-bound principal’s immutable kind. Each rule has an empty payload and admits only its exact method.

The JOSE header must be exact {alg:"EdDSA", typ:"vnd.sudomimus.public-key-assertion+jwt",kid:"pky_..."}. Claims must be exact iss, aud, iat, exp, jti, and requestHash; iss equals kid, aud is sudomimus-native-public-key, lifetime is at most 60 seconds, and requestHash is base64url SHA-256 of the exact request-body bytes. Every retry uses a new random 128-bit jti.

Media typeapplication/json
object
applicationAnchor
required

Public anchor identifying the integrating application.

string
Examplegenerated
{
"applicationAnchor": "example"
}

Tokens issued.

Media typeapplication/json
object
claims
required

Per-claim view across the five shareable claims, carried on both the 200 (why is a claim absent from the minted token) and the claim-gate 403 (what is still owed).

object
email
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
firstName
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
lastName
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
staticAvatar
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
animatedAvatar
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
applicationAnchor
required
string
accessToken
required

Account credentials use media type vnd.sudomimus.application-access+jwt. Workload credentials use vnd.sudomimus.workload-access+jwt and add exact act: {sub: <pairwise-workload-subject>}. In both cases payload sub is the owner Account’s pairwise sector subject, sid identifies the session, and jti identifies this token instance. The token contains no profile claims or raw Account/Workload identifier; use Session API /userinfo for current shared data.

string
refreshToken
required

Long-lived refresh token JWT with stable payload sid, version identifier jti, and positive rotationVersion. It contains no user identifier. Use Session API /refresh for renewal without re-presenting the access key.

string
Example
{
"claims": {
"email": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"firstName": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"lastName": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"staticAvatar": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"animatedAvatar": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
}
}
}
Cache-Control
string
Allowed values: no-store

Prevent storage of the credential-bearing response.

Pragma
string
Allowed values: no-cache

Legacy cache instruction retained for credential responses.

Malformed request body or public-key assertion syntax.

Media typeapplication/json

Error response body. Known failures may include a stable reason. Some failures are status-only and have an empty body. A missing, malformed, or structurally invalid JSON body returns InvalidBody.

object
reason

Stable machine-readable reason code.

string
Examplegenerated
{
"reason": "example"
}

Reason PublicKeyDirectDenied: the credential or signed assertion was rejected without revealing whether the key exists or which principal owns it.

Media typeapplication/json

Error response body. Known failures may include a stable reason. Some failures are status-only and have an empty body. A missing, malformed, or structurally invalid JSON body returns InvalidBody.

object
reason

Stable machine-readable reason code.

string
Examplegenerated
{
"reason": "example"
}

Application rule, Account lifecycle, email-domain policy, or claim requirements refused issuance. Claim-gate responses use the same claims and errand handoff as AccessKey issuance.

Media typeapplication/json

403 body. For the claim-gate reasons (ClaimConsentRequired, RequiredClaimDataMissing) the claims view and the errand handoff are present; for every other reason only reason is set.

object
reason
required

Stable machine-readable reason code.

string
claims

Per-claim view across the five shareable claims, carried on both the 200 (why is a claim absent from the minted token) and the claim-gate 403 (what is still owed).

object
email
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
firstName
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
lastName
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
staticAvatar
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
animatedAvatar
required

One shareable claim: what the application requests (requirement) joined with the user’s standing decision (state). UNKNOWN means the user was never asked; DENIED means the user explicitly declined.

object
requirement
required

The developer’s policy for the claim. SYNTHETIC_ONLY always emits the generated placeholder and never asks for real data. SYNTHETIC_FALLBACK guarantees the claim is present but uses a generated placeholder (a stand-in name, a proxy email, or a generated avatar) when the user has not shared real data. Unlike REQUIRED, neither synthetic mode blocks issuance or raises an errand.

string
Allowed values: SYNTHETIC_ONLY OFF OPTIONAL REQUIRED SYNTHETIC_FALLBACK
state
required
string
Allowed values: UNKNOWN GRANTED DENIED
errand

The browser side-trip that unblocks a claim-gated direct-issue: a short-lived, single-use bearer URL where the user authenticates when required, completes missing data, and manages consent. Open the URL and let the browser page guide the user.

object
errandKey
required

Bearer key (ernd_…); also the status-poll path key.

string
url
required

Open this in the user’s system browser.

string format: uri
expiresAt
required
string format: date-time
Example
{
"claims": {
"email": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"firstName": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"lastName": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"staticAvatar": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
},
"animatedAvatar": {
"requirement": "SYNTHETIC_ONLY",
"state": "UNKNOWN"
}
}
}

Application anchor not found.

Media typeapplication/json

Error response body. Known failures may include a stable reason. Some failures are status-only and have an empty body. A missing, malformed, or structurally invalid JSON body returns InvalidBody.

object
reason

Stable machine-readable reason code.

string
Examplegenerated
{
"reason": "example"
}

The assertion jti was already seen, or identity authority changed during issuance. Sign a fresh assertion and retry the complete exchange.

Media typeapplication/json

Error response body. Known failures may include a stable reason. Some failures are status-only and have an empty body. A missing, malformed, or structurally invalid JSON body returns InvalidBody.

object
reason

Stable machine-readable reason code.

string
Examplegenerated
{
"reason": "example"
}

Too many public-key attempts. Back off before retrying.

Public-key issuance failed with an empty response body.

Public-key issuance is temporarily unavailable.

Error response.

Media typeapplication/json

Error response body. Known failures may include a stable reason. Some failures are status-only and have an empty body. A missing, malformed, or structurally invalid JSON body returns InvalidBody.

object
reason

Stable machine-readable reason code.

string
Examplegenerated
{
"reason": "example"
}