Skip to main content

Scopes & Claims

This page documents every scope supported by mwen.io, the claims each produces, the credential format, and how to handle them in your application.


Scope overview

Scopes are declared in MwenClientConfig.scopes and determine what the extension asks the user to share. The user sees each requested claim individually on the consent screen and can toggle any of them off.

Your application must handle the case where a claim is absent — the user may have hidden it or may not have set a value in their profile.


Scope reference

openid

ClaimTypeFormatNotes
(none)Required by the SIOP v2 protocol. Carries no claims. Always include as the first scope.

identity

ClaimTypeFormatNotes
substringN/AThe user's per-app did:jwk. Always included — cannot be hidden or denied. Not selectively disclosable.

identity is implicitly included in every authentication. You do not need to list it explicitly.


name

ClaimTypeFormatNotes
given_namestringvc+sd-jwtUser's first name. Independently disclosable.
family_namestringvc+sd-jwtUser's last name. Independently disclosable.
// Example claim value in session.claims
session.claims?.given_name // { value: 'Alice', format: 'vc+sd-jwt' }
session.claims?.family_name // { value: 'Smith', format: 'vc+sd-jwt' }

nickname

ClaimTypeFormatNotes
nicknamestringvc+sd-jwtUser-chosen display name. Independently disclosable.

age

ClaimTypeFormatNotes
age_over_18booleanvc+bbsZero-knowledge proof. true if the user is over 18. Birth date is never revealed.
age_over_21booleanvc+bbsZero-knowledge proof. true if the user is over 21.
age_over_13booleanvc+bbsZero-knowledge proof. true if the user is over 13.

The age scope uses BBS+ signatures to generate derived proofs. The user's birth date is never transmitted to your app in any form.

session.claims?.age_over_18  // { value: true, format: 'vc+bbs', zkProof: true }

You cannot request only age_over_21 without also getting age_over_18 and age_over_13. All three predicates are produced together when the age scope is granted.


birthdate

ClaimTypeFormatNotes
birth_datestringvc+sd-jwtISO 8601 date (e.g. "1990-05-15"). The user can hide this.

This scope provides the raw birth date. If you need only age gating, use age instead — it avoids handling birth dates entirely.


country

ClaimTypeFormatNotes
countrystringvc+sd-jwtISO 3166-1 alpha-2 country code (e.g. "TT", "GB", "US").

email

ClaimTypeFormatNotes
emailstringvc+sd-jwtThe user's email address. Independently disclosable.
email_verifiedbooleanvc+sd-jwtWhether the email was verified by a third-party issuer. Independently disclosable.
session.claims?.email           // { value: '[email protected]', format: 'vc+sd-jwt' }
session.claims?.email_verified // { value: true, format: 'vc+sd-jwt' }

Note: for self-attested credentials, email_verified reflects the user's own attestation, not external verification. Third-party issuer verification is a planned future feature.


phone

ClaimTypeFormatNotes
phone_numberstringvc+sd-jwtE.164 format (e.g. "+18005551234").
phone_verifiedbooleanvc+sd-jwtWhether the phone number was externally verified.

address

ClaimTypeFormatNotes
street_addressstringvc+sd-jwtStreet address. Independently disclosable.
localitystringvc+sd-jwtCity / town.
regionstringvc+sd-jwtState / province.
postal_codestringvc+sd-jwtPostal / ZIP code.

Each address sub-claim is independently disclosable — the user may share locality without sharing street_address.


Credential formats

FormatUsed byWhat it means
vc+sd-jwtAll scopes except ageAn SD-JWT Verifiable Credential. Claim values are disclosed in plaintext when the user consents.
vc+bbsage scope onlyA BBS+ signed credential with a derived zero-knowledge proof. The underlying value is never disclosed.

Handling missing claims

The user may hide a claim or may not have set a value in their profile. A missing claim is simply absent from session.claims — it is never transmitted as null or undefined.

Always guard against absent claims:

const { session } = useMwen();

// Safe pattern
const name = session?.claims?.given_name?.value as string | undefined;
const isAdult = session?.claims?.age_over_18?.value as boolean | undefined;

// Render conditionally
if (isAdult === false) {
// Proof was returned and user is NOT over 18
}
if (isAdult === undefined) {
// Claim was not shared — treat as unknown, not as denied
}

The distinction between false (proof returned, predicate failed) and undefined (claim absent) is significant — do not conflate them.