Skip to content

Identity claims and sharing

View as Markdown

Beyond a stable identifier, an application often wants a little profile data — the user’s email, first name, or last name. Sudomimus treats each of these as a claim that is shared only with explicit agreement on both sides. Each of the three claims is gated independently, and sharing has two halves:

  • The claim policy — set by the developer, per application: which claims the application requests, and how strongly.
  • The claim grant — set by the user, per application: which claims they have agreed to share.

A claim lands in a token only when the policy requests it and the user has granted it. For OIDC, the relevant scope must also be requested. The user stays in control, and a revoked claim stops being shared on the very next token.

On your application’s detail page in the With portal, you set each of the three claims to one of:

PolicyMeaning
OffNever requested. The claim is never shared, regardless of what the user would allow.
OptionalRequested, but the user may decline. If they decline, the application simply does not receive it.
RequiredThe application needs it. The user must grant it to finish logging in.
SyntheticAlways provided — but the value may be a generated placeholder. The user sees it like Optional; if they decline (or the account holds no real data), the application receives a stand-in (a placeholder name, a proxy …@proxy.sudomimus.email address) instead of nothing. It never blocks login and never raises an errand.

An application created before you configure a policy requests nothing — there is no silent backfill. You opt into each claim deliberately.

The first time a user logs in to an application that requests claims, Sudomimus shows a consent screen:

  • Required claims are shown as locked-on — granting them is part of completing the login.
  • Optional claims are shown as checkboxes, unchecked by default — the user opts in.
  • Synthetic claims are shown like optional checkboxes too, with one difference disclosed in the copy: leaving one unchecked sends the application a placeholder value rather than nothing.

Their decision is remembered as one of three states — granted, denied, or not yet decided — so a declined optional claim is not nagged about again, while a claim they have never seen is asked about on the next interactive login.

A user can review and change every decision in the Data sharing view of their account portal: it lists each application they share claims with, whether each claim is currently shared, and whether the application requires it, with a Revoke action per application. Because grants are read live at every token issue, revoking takes effect immediately — the next token simply omits the claim.

For a given claim, the rule is:

the policy is not Off, and the user has granted it — and, for OIDC, the matching scope was requested.

The OIDC scope gate maps as follows:

  • email scope → the email claim
  • profile scope → first name and last name

Non-OIDC flows (Connect redeem/refresh, native direct-issue) have no scope gate — policy + grant alone decide.

A synthetic claim is the exception to “granted or omitted”: it is always present. When the user has granted real data the token carries that; otherwise it carries a stable, per-application placeholder (a generated name, a …@proxy.sudomimus.email proxy address). So a synthetic claim never blocks a login and is never omitted — the application is just told, for an OIDC email, that the address is unverified.

Required claims and non-interactive logins

Section titled “Required claims and non-interactive logins”

A required claim can only be satisfied by an interactive grant — and, where it is a data claim like email, by the account actually having that data. So the non-interactive issue points reject any login that would mint a token missing a required claim, with one of two reasons:

  • ClaimConsentRequired — the user has not granted a required claim.
  • RequiredClaimDataMissing — the user has granted it, but the account lacks the underlying data (e.g. a Steam account with no email).

This guarantee — that a required claim is always present in a minted token, never silently dropped — is what the rejection protects. It covers native direct-issue, token refresh, and the OIDC token endpoint.

How the user clears it depends on the client:

  • Native clients (Steam / AccessKey direct-issue) have no interactive login to the application, so the 403 carries an Errand — a browser side-trip where the user signs in (if data is being written), supplies the missing data, and grants consent. The client then retries. For an AccessKey, the same consent can also be collected up front, at the moment the user creates the key in the portal.
  • Browser / OIDC clients clear it on the next ordinary interactive login to that application, where the consent screen is shown inline.

An ungranted optional claim never blocks anything — it is just omitted. A synthetic claim never blocks either — it falls back to a placeholder, so it is the way to guarantee a value is present without ever forcing a user through a browser side-trip.

Whenever Sudomimus issues or refreshes a token through Connect or native direct-issue (/redeem, /refresh, /direct-issue/*), the response carries a top-level claims block alongside the tokens. It answers the question a missing claim otherwise leaves open: why isn’t this claim in my token?

{
"email": { "requirement": "REQUIRED", "state": "GRANTED" },
"firstName": { "requirement": "OPTIONAL", "state": "DENIED" },
"lastName": { "requirement": "OFF", "state": "UNKNOWN" }
}

For each of the three claims you get its requirement (the developer’s policy: OFF / OPTIONAL / REQUIRED / SYNTHETIC) joined with its state (the user’s standing decision: UNKNOWN / GRANTED / DENIED). The distinction between UNKNOWN (“never asked”) and DENIED (“explicitly declined”) is the reason this is three states and not a nullable boolean.

Read together with the inclusion rule above, the block tells you exactly why a claim is present or absent — policy OFF, never asked, declined, or granted but with no data behind it. On the claim-gate 403 from direct-issue, the same block is what lists what is still owed before tokens can be minted.

  • Connect / native access tokensemailAddress, firstName, and lastName each appear only when their claim is shared.
  • OIDC id_token / /userinfo — gated by scope and grant: the email claim becomes email (plus email_verified); first name becomes given_name; last name becomes family_name; name is composed from the granted parts. A synthetic email is sent with email_verified: false — it is a proxy address, not a verified mailbox, so do not treat it as one.

See Tokens and verification for where these sit in the token payloads.

  • Developer — your application’s detail page in the With portal: set each claim to Off / Optional / Required / Synthetic.
  • User — the Data sharing view in the account portal: see and revoke what each application receives.