Exchange an Ed25519 public-key assertion for application tokens.
const url = 'https://native-api.sudomimus.com/direct-issue/public-key';const options = { method: 'POST', headers: {Authorization: '<Authorization>', 'Content-Type': 'application/json'}, body: '{"applicationAnchor":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Public anchor identifying the integrating application.
Examplegenerated
{ "applicationAnchor": "example"}Responses
Section titled “ Responses ”Tokens issued.
object
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
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
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.
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
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.
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
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.
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
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.
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
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.
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.
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.
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" } }}Headers
Section titled “Headers”Prevent storage of the credential-bearing response.
Legacy cache instruction retained for credential responses.
Malformed request body or public-key assertion syntax.
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
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}Reason PublicKeyDirectDenied: the credential or signed assertion
was rejected without revealing whether the key exists or which
principal owns it.
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
Stable machine-readable reason code.
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.
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
Stable machine-readable reason code.
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
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
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.
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
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.
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
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.
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
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.
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
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.
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
Bearer key (ernd_…); also the status-poll path key.
Open this in the user’s system browser.
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.
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
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}The assertion jti was already seen, or identity authority changed
during issuance. Sign a fresh assertion and retry the complete
exchange.
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
Stable machine-readable reason code.
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.
default
Section titled “default”Error response.
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
Stable machine-readable reason code.
Examplegenerated
{ "reason": "example"}