Skip to content

Identity claims and sharing

View as Markdown

Beyond a stable identifier, an application may need profile data such as the user’s email, first name, last name, static avatar, or animated avatar. Sudomimus treats these as five separate claims. 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 is returned by UserInfo 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 next UserInfo request.

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

Policy Meaning
Off Never requested. The claim is never shared, regardless of what the user would allow.
Optional Requested, but the user may decline. If they decline, the application simply does not receive it.
Required The application needs it. The user must grant it to finish logging in.
Placeholder only (SYNTHETIC_ONLY) Always provided as a generated placeholder and never asks for or shares the user’s real data.
Fallback placeholder (SYNTHETIC_FALLBACK) Always provided. If the user grants real data, the real value is shared; otherwise the application receives a generated stand-in (a placeholder name, a proxy …@proxy.sudomimus.email address, or a generated avatar). It never blocks login and never raises an errand.

By default, email, first name, last name, and static avatar use Placeholder only. Animated avatar is Off. This gives new applications a useful placeholder identity without sharing real profile data. Set any claim to Off when you want it omitted completely.

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.
  • Fallback placeholder 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.
  • Placeholder only claims are not shown as consent choices because they never share real data.

Their decision is remembered as one of three states — granted, denied, or not yet decided. A denied optional claim is not requested again; a claim that is not yet decided is shown 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 by UserInfo, revoking takes effect immediately — the next UserInfo response omits the claim.

For a given claim, the rule is:

the policy permits a value, the user’s grant state permits the real value if real data is requested, and, for OIDC, the matching scope was requested.

flowchart TD
    Request["Evaluate one claim for session authority and UserInfo"] --> OIDC{"OIDC session?"}
    OIDC -->|Yes| Scope{"Matching scope requested?"}
    Scope -->|No| Omit["Omit the claim"]
    Scope -->|Yes| Policy{"Claim policy"}
    OIDC -->|No — Session API| Policy

    Policy -->|OFF| Omit
    Policy -->|SYNTHETIC_ONLY| Placeholder["Return a placeholder"]
    Policy -->|OPTIONAL| Optional{"Real data granted and present?"}
    Optional -->|Yes| Real["Return real data"]
    Optional -->|No| Omit
    Policy -->|REQUIRED| Required{"Real data granted and present?"}
    Required -->|Yes| Real
    Required -->|No| Block["Block issuance or refresh<br/>before UserInfo"]
    Policy -->|SYNTHETIC_FALLBACK| Fallback{"Real data granted and present?"}
    Fallback -->|Yes| Real
    Fallback -->|No| Placeholder

The OIDC scope gate maps as follows:

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

Ordinary application sessions use Session API /userinfo and have no scope gate — policy + grant alone decide. OIDC sessions use the discovered OIDC /userinfo endpoint.

The placeholder modes are the exception to “granted or omitted”: SYNTHETIC_ONLY is always present as a placeholder, and SYNTHETIC_FALLBACK is present as real data when granted or as a placeholder otherwise. Placeholders are stable per account and sector: generated names, a …@proxy.sudomimus.email proxy address, and a generated avatar URL. A placeholder 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 needs an interactive grant and the underlying account data. Non-interactive sign-in is rejected when that requirement is not met, 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 required claim authority is satisfied before a session can issue or refresh — 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. Placeholder modes never block either, so they are 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, Session API, or native direct-issue (/redeem, /refresh, /direct-issue/*), the response carries a top-level claims block alongside the tokens. It describes the policy and consent state that UserInfo will apply.

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

For each claim you get its requirement (the developer’s policy: SYNTHETIC_ONLY / OFF / OPTIONAL / REQUIRED / SYNTHETIC_FALLBACK) 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 why UserInfo may return or omit a claim — policy OFF, never asked, declined, or granted but with no data behind it. On the claim-gate 403 from direct-issue, the same block lists what is still owed before a session can be established.

For a live view after issuance, call Session GET /claim-state with the access token. Its claims map uses UserInfo names: email, given_name, family_name, picture, and picture_animated. OIDC clients discover the provider-specific claim_state_endpoint; its response contains only the state entries covered by the session’s email and profile scopes. name and email_verified have no separate state because they are derived from other claims.

  • Application access, refresh, and OIDC ID tokens — carry no profile claims.
  • Session /userinfo — gated by policy and grant, without an OIDC scope gate.
  • OIDC /userinfo — gated by scope and grant: the email claim becomes email (plus email_verified); first name becomes given_name; last name becomes family_name; static avatar becomes picture; animated avatar becomes picture_animated; name is composed from the granted name 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 the minimal token layouts and UserInfo endpoint. Avatar delivery also has URL scoping, revocation, and caching rules; see Avatar claims and delivery.

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