Skip to content

Native claims and the Errand

View as Markdown

Steam ticket and AccessKey direct-issue authenticate without an application login page. That keeps the happy path short, but it also means the client cannot display a consent form or ask the user to complete missing profile data.

This page covers both sides of that constraint:

  1. Choose claim policies that fit a non-interactive client.
  2. Handle the Errand browser handoff when a required real claim cannot yet be issued.

The shared policy and consent model is documented in Identity claims and sharing.

PolicyNative direct-issue behavior
OffNever requested.
OptionalShared only if the user already granted it. Never blocks, so a native-only user may never be prompted.
RequiredGuaranteed present with real data. Missing consent or data returns 403 with an Errand.
SyntheticGuaranteed present, using real data when granted and a stable placeholder otherwise. Never blocks and never creates an Errand.

For most native integrations, prefer SYNTHETIC over REQUIRED unless you specifically need verified real data.

  • Need a stable name or email-shaped value, and a placeholder is acceptable: use SYNTHETIC.
  • Need a real verified email for delivery or reconciliation: use REQUIRED and implement the Errand flow.
  • Want real data when already granted but can continue without it: use OPTIONAL.

If every requested claim is OFF or SYNTHETIC, claim policy can never force direct-issue into a browser handoff.

Synthetic names are generated placeholders. Synthetic emails use a stable …@proxy.sudomimus.email address. Proxy delivery is best-effort, not guaranteed, and OIDC exposes synthetic email with email_verified: false.

An Errand is short-lived account remediation, not token issuance. When direct-issue cannot satisfy a required claim, its 403 response gives the client a browser URL. The user completes consent or missing profile work there, then the client retries the original direct-issue.

Only two claim-gate reasons carry an Errand:

403 reasonMeaningBrowser work
ClaimConsentRequiredA required claim has not been granted.Grant consent and, when necessary, first add the missing data.
RequiredClaimDataMissingConsent exists, but the account lacks the real value.Register an email or complete the missing name.

Other 403 responses, such as rule denial or a disabled account, are terminal and do not include an Errand.

{
"reason": "ClaimConsentRequired",
"claims": {
"email": { "requirement": "REQUIRED", "state": "UNKNOWN" },
"firstName": { "requirement": "OPTIONAL", "state": "UNKNOWN" },
"lastName": { "requirement": "OFF", "state": "UNKNOWN" }
},
"errand": {
"errandKey": "ernd_...",
"url": "https://via.sudomimus.com/errand?key=ernd_...",
"expiresAt": "2026-06-10T12:30:00Z"
}
}
  • Open errand.url in the user’s system browser.
  • Treat errandKey as a bearer secret. It is also used to poll status.
  • The Errand is single-use and expires after 30 minutes.
native client ── direct-issue ──▶ 403 { reason, claims, errand }
├── open errand.url in the system browser
├── poll GET /errand/{errandKey}/status
└── on COMPLETED, retry direct-issue once ──▶ 200 { tokens, claims }

Polling is optional. A client may instead ask the user to confirm that they finished in the browser before retrying.

Terminal window
curl https://native-api.sudomimus.com/errand/ernd_.../status
# → { "status": "PENDING" }
# → { "status": "COMPLETED" }
# → { "status": "EXPIRED" }

Poll about every two seconds with a sensible overall timeout. EXPIRED deliberately covers unknown, malformed, consumed, and genuinely expired keys; rerun direct-issue to obtain a fresh handoff. The status endpoint never issues tokens.

Retries normally return the same live Errand when it has at least 15 minutes remaining and the required work has not changed. This prevents an eager retry loop from splitting user progress across multiple URLs.

  • Consent only: no additional sign-in is required because the credential holder already proved control of a token-minting credential.
  • Writing identity data: the browser requires sign-in, and the signed-in account must match the account resolved from the Steam ticket or AccessKey.
  • Optional and synthetic claims never create an Errand.
  • Connect /refresh and OIDC /token do not embed Errand handoffs. A native session blocked during refresh recovers by running direct-issue again.