diff --git a/docs/kratos/social-signin/84_uaepass.mdx b/docs/kratos/social-signin/84_uaepass.mdx index 52a0c2c51..f340eec72 100644 --- a/docs/kratos/social-signin/84_uaepass.mdx +++ b/docs/kratos/social-signin/84_uaepass.mdx @@ -6,6 +6,13 @@ sidebar_label: UAE PASS # UAE PASS +:::note + +To add UAE PASS as a social sign-in provider, you need a UAE PASS integration account. Visit [UAE PASS](https://docs.uaepass.ae) +to register your application. For testing, use the staging credentials `sandbox_stage` / `sandbox_stage`. + +::: + [UAE PASS](https://uaepass.ae/) is the UAE's official digital identity platform. It allows UAE nationals, residents, and visitors to authenticate using their UAE digital identity. Ory supports both web and mobile authentication flows for UAE PASS. @@ -39,45 +46,187 @@ schema. To define the mapping, create a Jsonnet code snippet. Read [this document](./data-mapping) to learn more about Jsonnet data mapping. -In this sample Jsonnet snippet, the user's `email` and `fullnameEN` are mapped to the identity schema. +**Basic mapping** (email and name): ```jsonnet local claims = std.extVar('claims'); +{ + identity: { + traits: { + [if 'email' in claims then 'email' else null]: claims.email, + name: { + first: claims.given_name, + last: claims.family_name, + }, + }, + }, +} +``` + +**Full mapping** (with UAE PASS metadata and verified email): +```jsonnet +local claims = std.extVar('claims'); +local hasRaw = 'raw_claims' in claims; +local raw = if hasRaw then claims.raw_claims else {}; +local titleCase(s) = + local words = std.split(s, ' '); + std.join(' ', [ + if std.length(w) == 0 then '' + else std.asciiUpper(w[0]) + std.asciiLower(w[1:]) + for w in words + ]); { identity: { traits: { - [if 'sub' in claims then 'subject' else null]: claims.sub, [if 'email' in claims then 'email' else null]: claims.email, - [if 'fullnameEN' in claims then 'name' else null]: claims.fullnameEN, + [if 'mobile' in raw then 'phone' + else if 'phone_number' in claims then 'phone' + else null]: + if 'mobile' in raw then raw.mobile + else if 'phone_number' in claims then claims.phone_number, + name: { + first: titleCase(claims.given_name), + last: titleCase(claims.family_name), + }, + }, + verified_addresses: [ + if 'email' in claims then { + via: 'email', + value: claims.email, + verified: true, + }, + ], + [if hasRaw then 'metadata_public' else null]: { + uaepass: { + [if 'uuid' in raw then 'uuid' else null]: raw.uuid, + [if 'userType' in raw then 'user_type' else null]: raw.userType, + [if 'mobile' in raw then 'mobile' else null]: raw.mobile, + [if 'email' in raw then 'email' else null]: raw.email, + [if 'firstnameEN' in raw then 'firstname_en' else null]: raw.firstnameEN, + [if 'lastnameEN' in raw then 'lastname_en' else null]: raw.lastnameEN, + [if 'firstnameAR' in raw then 'firstname_ar' else null]: raw.firstnameAR, + [if 'lastnameAR' in raw then 'lastname_ar' else null]: raw.lastnameAR, + [if 'fullnameEN' in raw then 'fullname_en' else null]: raw.fullnameEN, + [if 'fullnameAR' in raw then 'fullname_ar' else null]: raw.fullnameAR, + [if 'nationalityEN' in raw then 'nationality_en' else null]: raw.nationalityEN, + [if 'nationalityAR' in raw then 'nationality_ar' else null]: raw.nationalityAR, + [if 'gender' in raw then 'gender' else null]: raw.gender, + [if 'idn' in raw then 'emirates_id' else null]: raw.idn, + [if 'idType' in raw then 'id_type' else null]: raw.idType, + [if 'spuuid' in raw then 'smartpass_uuid' else null]: raw.spuuid, + [if 'titleEN' in raw then 'title_en' else null]: raw.titleEN, + [if 'titleAR' in raw then 'title_ar' else null]: raw.titleAR, + [if 'profileType' in raw then 'profile_type' else null]: raw.profileType, + [if 'unifiedId' in raw then 'unified_id' else null]: raw.unifiedId, + }, }, }, } ``` - - -Follow these steps to add UAE PASS as a social sign-in provider to your project using the Ory CLI: +:::info -1. Register your application on the [UAE PASS partner portal](https://uaepass.ae/). You will receive a Client ID - and Client Secret. -1. In the created app, set the redirect URI to: +UAE PASS returns different attributes depending on the user's account level (SOP): - ```shell - https://$PROJECT_SLUG.projects.oryapis.com/self-service/methods/oidc/callback/uaepass - ``` +| Level | Name | Available Attributes | +|-------|-------------|---------------------| +| SOP1 | Basic | uuid, email, mobile, firstnameEN, lastnameEN, userType | +| SOP2 | Advanced | All SOP1 + full names (EN/AR), nationality, gender, idn, idType | +| SOP3 | Qualified | All SOP2 + titleEN/AR, profileType, unifiedId | + +All raw attributes are accessible via `claims.raw_claims.*` in the Jsonnet mapper. Always guard access to +`raw_claims` with `'raw_claims' in claims` to avoid runtime errors if the field is not populated. + +UAE PASS returns names in **uppercase** (e.g., `"MOHAMMED ALI"`). Use a `titleCase` helper in your mapper to +normalize names before storing them in traits. + +::: + + + + +Follow these steps to add UAE PASS as a social sign-in provider to your project using the Ory CLI or self-hosted Kratos: 1. Create a Jsonnet code snippet to map the desired claims to the Ory Identity schema. + UAE PASS doesn't return an `id_token`. Ory sends requests to UAE PASS's userinfo API and adds the user info to + `std.extVar('claims')`. All UAE PASS-specific attributes are available via `claims.raw_claims`. + + **Basic mapping** (email and name): + ```jsonnet local claims = std.extVar('claims'); + { + identity: { + traits: { + [if 'email' in claims then 'email' else null]: claims.email, + name: { + first: claims.given_name, + last: claims.family_name, + }, + }, + }, + } + ``` + **Full mapping** (with UAE PASS metadata and verified email): + + ```jsonnet + local claims = std.extVar('claims'); + local hasRaw = 'raw_claims' in claims; + local raw = if hasRaw then claims.raw_claims else {}; + local titleCase(s) = + local words = std.split(s, ' '); + std.join(' ', [ + if std.length(w) == 0 then '' + else std.asciiUpper(w[0]) + std.asciiLower(w[1:]) + for w in words + ]); { identity: { traits: { - [if 'sub' in claims then 'subject' else null]: claims.sub, [if 'email' in claims then 'email' else null]: claims.email, - [if 'fullnameEN' in claims then 'name' else null]: claims.fullnameEN, + [if 'mobile' in raw then 'phone' + else if 'phone_number' in claims then 'phone' + else null]: + if 'mobile' in raw then raw.mobile + else if 'phone_number' in claims then claims.phone_number, + name: { + first: titleCase(claims.given_name), + last: titleCase(claims.family_name), + }, + }, + verified_addresses: [ + if 'email' in claims then { + via: 'email', + value: claims.email, + verified: true, + }, + ], + [if hasRaw then 'metadata_public' else null]: { + uaepass: { + [if 'uuid' in raw then 'uuid' else null]: raw.uuid, + [if 'userType' in raw then 'user_type' else null]: raw.userType, + [if 'mobile' in raw then 'mobile' else null]: raw.mobile, + [if 'email' in raw then 'email' else null]: raw.email, + [if 'firstnameEN' in raw then 'firstname_en' else null]: raw.firstnameEN, + [if 'lastnameEN' in raw then 'lastname_en' else null]: raw.lastnameEN, + [if 'firstnameAR' in raw then 'firstname_ar' else null]: raw.firstnameAR, + [if 'lastnameAR' in raw then 'lastname_ar' else null]: raw.lastnameAR, + [if 'fullnameEN' in raw then 'fullname_en' else null]: raw.fullnameEN, + [if 'fullnameAR' in raw then 'fullname_ar' else null]: raw.fullnameAR, + [if 'nationalityEN' in raw then 'nationality_en' else null]: raw.nationalityEN, + [if 'nationalityAR' in raw then 'nationality_ar' else null]: raw.nationalityAR, + [if 'gender' in raw then 'gender' else null]: raw.gender, + [if 'idn' in raw then 'emirates_id' else null]: raw.idn, + [if 'idType' in raw then 'id_type' else null]: raw.idType, + [if 'spuuid' in raw then 'smartpass_uuid' else null]: raw.spuuid, + [if 'titleEN' in raw then 'title_en' else null]: raw.titleEN, + [if 'titleAR' in raw then 'title_ar' else null]: raw.titleAR, + [if 'profileType' in raw then 'profile_type' else null]: raw.profileType, + [if 'unifiedId' in raw then 'unified_id' else null]: raw.unifiedId, + }, }, }, } @@ -85,10 +234,19 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project :::info - UAE PASS returns claims through its userinfo endpoint. Available claims include `sub`, `email`, - `fullnameEN`, `firstnameEN`, `lastnameEN`, `fullnameAR`, `firstnameAR`, `lastnameAR`, `gender`, `dob`, `mobile`, - `nationalityEN`, `userType`, `uuid`, `unifiedID`, and `idn`. Ory fetches these claims and makes them available in - `std.extVar('claims')`. + UAE PASS returns different attributes depending on the user's account level (SOP): + + | Level | Name | Available Attributes | + |-------|-------------|---------------------| + | SOP1 | Basic | uuid, email, mobile, firstnameEN, lastnameEN, userType | + | SOP2 | Advanced | All SOP1 + full names (EN/AR), nationality, gender, idn, idType | + | SOP3 | Qualified | All SOP2 + titleEN/AR, profileType, unifiedId | + + All raw attributes are accessible via `claims.raw_claims.*` in the Jsonnet mapper. Always guard access to + `raw_claims` with `'raw_claims' in claims` to avoid runtime errors if the field is not populated. + + UAE PASS returns names in **uppercase** (e.g., `"MOHAMMED ALI"`). Use a `titleCase` helper in your mapper to + normalize names before storing them in traits. ::: @@ -96,13 +254,13 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project ``` -1. Encode the Jsonnet snippet with [Base64](https://www.base64encode.org/) or host it under a URL accessible to Ory Network. +2. Encode the Jsonnet snippet with [Base64](https://www.base64encode.org/) or host it under a URL accessible to Ory Network. - ```shell - cat your-data-mapping.jsonnet | base64 - ``` + ```shell + cat your-data-mapping.jsonnet | base64 + ``` -1. Download the Ory Identities config from your project and save it to a file: +3. Download the Ory Identities config from your project and save it to a file: ```shell ## List all available workspaces @@ -115,30 +273,67 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project ory get identity-config --project --workspace --format yaml > identity-config.yaml ``` -1. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 +4. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 string or provide a URL to the file. + **Staging configuration:** + + ```yaml + selfservice: + methods: + oidc: + config: + providers: + - id: uaepass # this is `` in the Authorization callback URL. DO NOT CHANGE IT ONCE SET! + provider: uaepass + client_id: sandbox_stage + client_secret: sandbox_stage + auth_url: https://stg-id.uaepass.ae/idshub/authorize + token_url: https://stg-id.uaepass.ae/idshub/token + issuer_url: https://stg-id.uaepass.ae/idshub + mapper_url: "base64://{YOUR_BASE64_ENCODED_JSONNET_HERE}" + # Alternatively, use a URL: + # mapper_url: https://storage.googleapis.com/example-example-prd/example-file + scope: + - urn:uae:digitalid:profile:general + enabled: true + ``` + + **Production configuration:** + ```yaml selfservice: - methods: - oidc: - config: - providers: - - id: uaepass # this is `` in the Authorization callback URL. DO NOT CHANGE IT ONCE SET! - provider: uaepass - client_id: .... # Replace this with the Client ID from UAE PASS - client_secret: .... # Replace this with the Client Secret from UAE PASS - issuer_url: https://id.uaepass.ae # Use https://stg-id.uaepass.ae for staging - mapper_url: "base64://{YOUR_BASE64_ENCODED_JSONNET_HERE}" - # Alternatively, use an URL: - # mapper_url: https://storage.googleapis.com/abc-cde-prd/9cac9717f007808bf17f22ce7f4295c739604b183f05ac4afb4 - scope: - - urn:uae:digitalid:profile:general - - urn:uae:digitalid:profile:general:unifiedId - enabled: true + methods: + oidc: + config: + providers: + - id: uaepass + provider: uaepass + client_id: .... # Replace with your UAE PASS client ID + client_secret: .... # Replace with your UAE PASS client secret + auth_url: https://id.uaepass.ae/idshub/authorize + token_url: https://id.uaepass.ae/idshub/token + issuer_url: https://id.uaepass.ae/idshub + mapper_url: "base64://{YOUR_BASE64_ENCODED_JSONNET_HERE}" + scope: + - urn:uae:digitalid:profile:general + enabled: true + ``` + + :::tip + + For visitor integration, add extra scopes to retrieve `profileType` and `unifiedId`: + + ```yaml + scope: + - urn:uae:digitalid:profile:general + - urn:uae:digitalid:profile:general:profileType + - urn:uae:digitalid:profile:general:unifiedId ``` -1. Update the Ory Identities configuration using the file you worked with: + ::: + +5. Update the Ory Identities configuration using the file you worked with: ```shell ory update identity-config --project --workspace --file identity-config.yaml @@ -148,16 +343,36 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project ```` -## Configuration +## Configuration reference + +The `uaepass` provider handles the following UAE PASS requirements automatically: + +- **No OIDC discovery** — UAE PASS doesn't expose `.well-known/openid-configuration`. Endpoints are configured directly. +- **No `openid` scope** — UAE PASS doesn't support the standard `openid` scope. Use `urn:uae:digitalid:profile:general`. +- **`acr_values` injection** — The required `urn:safelayer:tws:policies:authentication:level:low` parameter is added + automatically. +- **`client_secret_basic` auth** — The token endpoint uses HTTP Basic authentication as required by UAE PASS. +- **Userinfo-based claims** — UAE PASS doesn't return ID tokens. Claims are fetched from the userinfo endpoint. -### Environments +### Endpoints -UAE PASS provides two environments. Set the `issuer_url` accordingly: +| Environment | Authorize | Token | Userinfo | Logout | +| ----------- | -------------------------------------------- | ---------------------------------------- | ------------------------------------------- | ----------------------------------------- | +| Staging | `https://stg-id.uaepass.ae/idshub/authorize` | `https://stg-id.uaepass.ae/idshub/token` | `https://stg-id.uaepass.ae/idshub/userinfo` | `https://stg-id.uaepass.ae/idshub/logout` | +| Production | `https://id.uaepass.ae/idshub/authorize` | `https://id.uaepass.ae/idshub/token` | `https://id.uaepass.ae/idshub/userinfo` | `https://id.uaepass.ae/idshub/logout` | -| Environment | Issuer URL | -| ----------- | --------------------------- | -| Production | `https://id.uaepass.ae` | -| Staging | `https://stg-id.uaepass.ae` | +### Configuration fields + +| Field | Required | Description | +| --------------- | -------- | ----------------------------------------------------------------------------------------------------- | +| `provider` | Yes | Must be `uaepass` | +| `client_id` | Yes | Your UAE PASS client ID (use `sandbox_stage` for staging) | +| `client_secret` | Yes | Your UAE PASS client secret (use `sandbox_stage` for staging) | +| `auth_url` | No | Authorization endpoint. Defaults to staging if omitted | +| `token_url` | No | Token endpoint. Defaults to staging if omitted | +| `issuer_url` | No | Base URL for deriving the userinfo endpoint (`{issuer_url}/userinfo`). Defaults to staging if omitted | +| `scope` | Yes | Must include `urn:uae:digitalid:profile:general` | +| `mapper_url` | Yes | Path or Base64-encoded Jsonnet mapper | ### Authentication flows @@ -189,6 +404,77 @@ mobile), UAE PASS defaults to the mobile flow. ::: +## Available claims + +UAE PASS doesn't return an `id_token`. Ory sends requests to UAE PASS's userinfo API and adds the user info to +`std.extVar('claims')`. + +### Standard claims + +These claims are mapped automatically by the provider and available directly on the `claims` object: + +| Claim | Field | Description | +| --------------------- | ----------- | ---------------------------------- | +| `claims.sub` | Subject | UUID (preferred) or sub identifier | +| `claims.given_name` | Given Name | `firstnameEN` from UAE PASS | +| `claims.family_name` | Family Name | `lastnameEN` from UAE PASS | +| `claims.name` | Full Name | `fullnameEN` from UAE PASS | +| `claims.email` | Email | Verified email | +| `claims.phone_number` | Phone | Mobile number | +| `claims.gender` | Gender | Gender | + +### UAE PASS-specific claims (raw_claims) + +These are accessible via `claims.raw_claims` in the Jsonnet mapper. Availability depends on the user's account level (SOP): + +| Claim | SOP Level | Description | +| -------------------------------- | --------------- | ------------------------------------------------- | +| `claims.raw_claims.uuid` | All | UAE PASS unique user identifier | +| `claims.raw_claims.userType` | All | Account type: `SOP1`, `SOP2`, or `SOP3` | +| `claims.raw_claims.mobile` | All | Verified phone number | +| `claims.raw_claims.email` | All | Verified email | +| `claims.raw_claims.firstnameEN` | All | Given name (English) | +| `claims.raw_claims.lastnameEN` | All | Family name (English) | +| `claims.raw_claims.firstnameAR` | SOP2+ | Given name (Arabic) | +| `claims.raw_claims.lastnameAR` | SOP2+ | Family name (Arabic) | +| `claims.raw_claims.fullnameEN` | SOP2+ | Full name (English) | +| `claims.raw_claims.fullnameAR` | SOP2+ | Full name (Arabic) | +| `claims.raw_claims.nationalityEN` | SOP2+ | Nationality (English) | +| `claims.raw_claims.nationalityAR` | SOP2+ | Nationality (Arabic) | +| `claims.raw_claims.gender` | SOP2+ | Gender | +| `claims.raw_claims.idn` | SOP2+ | Emirates ID number (citizens/residents only) | +| `claims.raw_claims.idType` | SOP2+ | ID type | +| `claims.raw_claims.spuuid` | SOP2+ | SmartPass UUID (SmartPass-verified accounts only) | +| `claims.raw_claims.titleEN` | SOP2+ | Title (English) | +| `claims.raw_claims.titleAR` | SOP2+ | Title (Arabic) | +| `claims.raw_claims.profileType` | SOP3 (Visitors) | `1` (Citizen/Resident) or `2` (Visitor) | +| `claims.raw_claims.unifiedId` | SOP3 (Visitors) | Unified user ID | + +:::caution + +The `idn` (Emirates ID) attribute is **not returned for Visitor profiles**. It is only available for Citizens and Residents with +SOP2 or SOP3 accounts. + +::: + +## User account types (SOP levels) + +UAE PASS supports three account levels, known as Standard Operating Procedures (SOPs). The account level determines which +attributes are returned in the userinfo response. + +| Level | Name | Verification Method | Available Attributes | +| ----- | --------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| SOP1 | Basic | Email + Mobile OTP only. Account is unverified. | uuid, email, mobile, firstnameEN, lastnameEN, userType | +| SOP2 | Advanced | Emirates ID + PIN, or migrated from SmartPass/Dubai ID. Account is verified. | All SOP1 + fullnameEN/AR, firstnameAR, lastnameAR, nationalityEN/AR, gender, idn, idType, spuuid, titleEN/AR | +| SOP3 | Qualified | Emirates ID + Biometrics (face or fingerprint). Account is verified. | All SOP2 + profileType, unifiedId | + +:::info + +SOP2 and SOP3 accounts have access to digital signature capabilities. SOP1 accounts only support authentication — they cannot use +digital signature or data/document sharing features. + +::: + ### Scopes UAE PASS uses custom scopes to control which user data is returned. The available scopes depend on the user type. @@ -210,72 +496,41 @@ UAE PASS uses custom scopes to control which user data is returned. The availabl For more information on scopes and endpoints, refer to the [UAE PASS documentation](https://docs.uaepass.ae/feature-guides/authentication/web-application/endpoints). -### User claims +### Visitor accounts -UAE PASS returns the following claims. Use these in your Jsonnet data mapping to populate identity traits. +Visitors (non-Citizens/non-Residents) have a different attribute set. Visitors only support SOP1 and SOP3 levels. To retrieve +visitor-specific attributes, add extra scopes to your configuration: -| Claim | Description | -| --------------- | ------------------------------ | -| `sub` | Subject identifier (unique ID) | -| `email` | Email address | -| `fullnameEN` | Full name (English) | -| `firstnameEN` | First name (English) | -| `lastnameEN` | Last name (English) | -| `fullnameAR` | Full name (Arabic) | -| `firstnameAR` | First name (Arabic) | -| `lastnameAR` | Last name (Arabic) | -| `uuid` | UUID identifier | -| `unifiedID` | UAE unified identifier | -| `idn` | Identity number | -| `userType` | Profile type (SOP1/SOP2/SOP3) | -| `nationalityEN` | Nationality | -| `gender` | Gender | -| `dob` | Date of birth | -| `mobile` | Mobile number | - -**User types:** +```yaml +scope: + - urn:uae:digitalid:profile:general + - urn:uae:digitalid:profile:general:profileType + - urn:uae:digitalid:profile:general:unifiedId +``` -- **SOP1**: UAE National -- **SOP2**: Resident -- **SOP3**: Visitor +You can distinguish visitor profiles from citizen/resident profiles using the `profileType` claim: -### Advanced data mapping +- `profileType = 1` → Citizen or Resident +- `profileType = 2` → Visitor -To map additional UAE PASS claims to your identity schema, use a more comprehensive Jsonnet snippet: +## Staging testing -```jsonnet -local claims = std.extVar('claims'); +Follow these steps to test your UAE PASS integration in the staging environment: -{ - identity: { - traits: { - [if 'sub' in claims then 'subject' else null]: claims.sub, - [if 'email' in claims then 'email' else null]: claims.email, - [if 'fullnameEN' in claims then 'name' else null]: { - full: claims.fullnameEN, - [if 'firstnameEN' in claims then 'first' else null]: claims.firstnameEN, - [if 'lastnameEN' in claims then 'last' else null]: claims.lastnameEN, - }, - [if 'fullnameAR' in claims then 'name_ar' else null]: { - full: claims.fullnameAR, - [if 'firstnameAR' in claims then 'first' else null]: claims.firstnameAR, - [if 'lastnameAR' in claims then 'last' else null]: claims.lastnameAR, - }, - [if 'unifiedID' in claims then 'unified_id' else null]: claims.unifiedID, - [if 'userType' in claims then 'user_type' else null]: claims.userType, - [if 'nationalityEN' in claims then 'nationality' else null]: claims.nationalityEN, - [if 'gender' in claims then 'gender' else null]: claims.gender, - [if 'dob' in claims then 'date_of_birth' else null]: claims.dob, - [if 'mobile' in claims then 'phone' else null]: claims.mobile, - }, - }, -} -``` +1. **Create a staging account**: Set up a UAE PASS staging account at + [docs.uaepass.ae](https://docs.uaepass.ae/start-test-environment-implementation/create-uaepass-user). Staging accounts can be + created from any location — there are no geographic restrictions. +2. **Use staging credentials**: `client_id: sandbox_stage`, `client_secret: sandbox_stage`. +3. **Upgrade your account** (optional): The staging account starts as SOP1 (basic). To test SOP2/SOP3 attributes, upgrade via the + [self-care portal](https://docs.uaepass.ae/quick-start-guide-uae-pass-staging-environment/upgrade-staging-uae-pass-account). +4. **Run a POC**: Follow the + [POC guide](https://docs.uaepass.ae/quick-start-guide-uae-pass-staging-environment/conduct-a-poc-with-uae-pass-authentication) + to verify the authentication flow end-to-end. :::note -Your Ory Identity schema must include the corresponding fields for any claims you map. Update your identity schema to include the -fields you need before configuring the data mapping. +UAE PASS APIs are publicly accessible — both staging and production endpoints work from overseas. There are currently no charges +for integrating with UAE PASS. ::: @@ -286,3 +541,19 @@ import SocialSigninTroubleshooting from '../_common/social-sign-in-troubleshooti ``` + +### UAE PASS-specific issues + +- **No attributes returned**: Check the user's SOP level. SOP1 accounts return only basic attributes (uuid, email, mobile, + firstnameEN, lastnameEN). Upgrade the staging account to SOP3 for full attribute testing. +- **Missing `idn` for visitors**: The Emirates ID (`idn`) attribute is not returned for Visitor profiles. This is expected + behavior. +- **Logout redirect issues**: UAE PASS only accepts a `state` parameter in the logout URL. To pass additional parameters, + Base64-encode them into the `state` parameter: + ``` + https://stg-id.uaepass.ae/idshub/logout?redirect_uri=https://your-app.com/logout&state={base64_encoded_query_string} + ``` + +### Credits + +This provider was developed by [GBYTE TECH](https://gbyte.tech/) and is available under the Apache 2.0 license.