---
title: Identity claims and sharing
description: How Sudomimus shares a user's email, first name, and last name with
  an application — the developer-set claim policy, the user-controlled grant,
  and how scopes gate what ends up in a token.
editUrl: true
head: []
template: doc
sidebar:
  order: 5
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

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.

## The claim policy (developer)

On your application's detail page in the [With portal](https://with.sudomimus.com), you set each of the three claims 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. |
| **Synthetic** | Always 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 user's grant

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.

## When a claim actually appears in a token

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

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](/en-us/native/claims-and-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](/en-us/native/overview/), 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.

## The `claims` block

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?

```json
{
  "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](#when-a-claim-actually-appears-in-a-token), 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.

## What the application receives

- **Connect / native access tokens** — `emailAddress`, `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](/en-us/concepts/tokens-and-verification/) for where these sit in the token payloads.

## Where to manage it

- **Developer** — your application's detail page in the [With portal](https://with.sudomimus.com): set each claim to Off / Optional / Required / Synthetic.
- **User** — the **Data sharing** view in the account portal: see and revoke what each application receives.