From b3bd53f7e758afcbb66b7c76287ba70575b97421 Mon Sep 17 00:00:00 2001 From: George Kutsurua Date: Mon, 23 Feb 2026 18:52:26 +0400 Subject: [PATCH 1/3] docs: extend UAE PASS social sign-in provider documentation Add comprehensive reference sections for the UAE PASS provider: - Configuration fields reference table - Available claims (standard + rawClaims) with SOP-level availability - User account types (SOP1/SOP2/SOP3) with verification methods - Visitor account details and profileType distinction - Build and deploy instructions for custom Kratos fork - Staging testing guide with links to UAE PASS docs - UAE PASS-specific troubleshooting (missing attributes, logout redirects) - Logout endpoint added to endpoints table --- docs/kratos/social-signin/100_uaepass.mdx | 412 ++++++++++++++++++++++ src/sidebar.ts | 1 + 2 files changed, 413 insertions(+) create mode 100644 docs/kratos/social-signin/100_uaepass.mdx diff --git a/docs/kratos/social-signin/100_uaepass.mdx b/docs/kratos/social-signin/100_uaepass.mdx new file mode 100644 index 000000000..01de12ddf --- /dev/null +++ b/docs/kratos/social-signin/100_uaepass.mdx @@ -0,0 +1,412 @@ +--- +id: uaepass +title: Add UAE PASS as a social sign-in provider in Ory +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`. + +::: + +````mdx-code-block +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +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.rawClaims`. + + **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 = 'rawClaims' in claims; + local raw = if hasRaw then claims.rawClaims 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 'email' in claims then 'email' else null]: claims.email, + [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, + }, + }, + }, + } + ``` + + :::info + + 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.rawClaims.*` in the Jsonnet mapper. Always guard access to + `rawClaims` with `'rawClaims' 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. + + ::: + +```mdx-code-block +import JsonnetWarning from '../../_common/jsonnetwarning.mdx' + + +``` + +2. Encode the Jsonnet snippet with [Base64](https://www.base64encode.org/) or host it under an URL accessible to Ory Network. + + ```shell + cat your-data-mapping.jsonnet | base64 + ``` + +3. Download the Ory Identities config from your project and save it to a file: + + ```shell + ## List all available workspaces + ory list workspaces + + ## List all available projects + ory list projects --workspace + + ## Get config + ory get identity-config --project --workspace --format yaml > identity-config.yaml + ``` + +4. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 + string or provide an 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 an 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 + 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 + ``` + + ::: + +5. Update the Ory Identities configuration using the file you worked with: + + ```shell + ory update identity-config --project --workspace --file identity-config.yaml + ``` + + + +```` + +## 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. + +### Endpoints + +| 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` | + +### 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 | + +## 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 (rawClaims) + +These are accessible via `claims.rawClaims` in the Jsonnet mapper. Availability depends on the user's account level (SOP): + +| Claim | SOP Level | Description | +| -------------------------------- | --------------- | ------------------------------------------------- | +| `claims.rawClaims.uuid` | All | UAE PASS unique user identifier | +| `claims.rawClaims.userType` | All | Account type: `SOP1`, `SOP2`, or `SOP3` | +| `claims.rawClaims.mobile` | All | Verified phone number | +| `claims.rawClaims.email` | All | Verified email | +| `claims.rawClaims.firstnameEN` | All | Given name (English) | +| `claims.rawClaims.lastnameEN` | All | Family name (English) | +| `claims.rawClaims.firstnameAR` | SOP2+ | Given name (Arabic) | +| `claims.rawClaims.lastnameAR` | SOP2+ | Family name (Arabic) | +| `claims.rawClaims.fullnameEN` | SOP2+ | Full name (English) | +| `claims.rawClaims.fullnameAR` | SOP2+ | Full name (Arabic) | +| `claims.rawClaims.nationalityEN` | SOP2+ | Nationality (English) | +| `claims.rawClaims.nationalityAR` | SOP2+ | Nationality (Arabic) | +| `claims.rawClaims.gender` | SOP2+ | Gender | +| `claims.rawClaims.idn` | SOP2+ | Emirates ID number (citizens/residents only) | +| `claims.rawClaims.idType` | SOP2+ | ID type | +| `claims.rawClaims.spuuid` | SOP2+ | SmartPass UUID (SmartPass-verified accounts only) | +| `claims.rawClaims.titleEN` | SOP2+ | Title (English) | +| `claims.rawClaims.titleAR` | SOP2+ | Title (Arabic) | +| `claims.rawClaims.profileType` | SOP3 (Visitors) | `1` (Citizen/Resident) or `2` (Visitor) | +| `claims.rawClaims.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. + +::: + +### Visitor accounts + +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: + +```yaml +scope: + - urn:uae:digitalid:profile:general + - urn:uae:digitalid:profile:general:profileType + - urn:uae:digitalid:profile:general:unifiedId +``` + +You can distinguish visitor profiles from citizen/resident profiles using the `profileType` claim: + +- `profileType = 1` → Citizen or Resident +- `profileType = 2` → Visitor + +## Build and deploy + +The `uaepass` provider requires a custom build of Ory Kratos from the +[fork with UAE PASS support](https://github.com/baytii/kratos). This is necessary because the provider is not yet part of the +upstream Ory Kratos distribution. + +```bash +# Clone the fork +git clone https://github.com/baytii/kratos.git +cd kratos + +# Build the custom Docker image +docker build -t your-registry/kratos:latest-uaepass . + +# Push to your registry +docker push your-registry/kratos:latest-uaepass +``` + +Then reference this image in your `docker-compose.yml` or Kubernetes deployment: + +```yaml +# docker-compose.yml +services: + kratos: + image: your-registry/kratos:latest-uaepass + # ... rest of your config +``` + +## Staging testing + +Follow these steps to test your UAE PASS integration in the staging environment: + +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 + +UAE PASS APIs are publicly accessible — both staging and production endpoints work from overseas. There are currently no charges +for integrating with UAE PASS. + +::: + +## Troubleshooting + +```mdx-code-block +import SocialSigninTroubleshooting from '../_common/social-sign-in-troubleshooting.mdx' + + +``` + +### 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. diff --git a/src/sidebar.ts b/src/sidebar.ts index cf2294cfb..ed1575323 100644 --- a/src/sidebar.ts +++ b/src/sidebar.ts @@ -59,6 +59,7 @@ const oidcSSO: SidebarItemConfig = { "kratos/social-signin/x-twitter", "kratos/social-signin/line", "kratos/social-signin/amazon", + "kratos/social-signin/uaepass", ], }, "kratos/social-signin/data-mapping", From 7c85daad4ade76d492e0141c63e93d7cb100d15e Mon Sep 17 00:00:00 2001 From: George Kutsurua Date: Fri, 13 Mar 2026 14:50:53 +0400 Subject: [PATCH 2/3] docs: merge UAE PASS documentation into single file Consolidate 100_uaepass.mdx into 84_uaepass.mdx, combining Ory Console setup instructions with comprehensive CLI/self-hosted guide, rawClaims documentation, SOP level details, staging testing steps, and credits. --- docs/kratos/social-signin/100_uaepass.mdx | 412 ------------------ docs/kratos/social-signin/84_uaepass.mdx | 481 +++++++++++++++++----- 2 files changed, 376 insertions(+), 517 deletions(-) delete mode 100644 docs/kratos/social-signin/100_uaepass.mdx diff --git a/docs/kratos/social-signin/100_uaepass.mdx b/docs/kratos/social-signin/100_uaepass.mdx deleted file mode 100644 index 01de12ddf..000000000 --- a/docs/kratos/social-signin/100_uaepass.mdx +++ /dev/null @@ -1,412 +0,0 @@ ---- -id: uaepass -title: Add UAE PASS as a social sign-in provider in Ory -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`. - -::: - -````mdx-code-block -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - - - -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.rawClaims`. - - **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 = 'rawClaims' in claims; - local raw = if hasRaw then claims.rawClaims 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 'email' in claims then 'email' else null]: claims.email, - [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, - }, - }, - }, - } - ``` - - :::info - - 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.rawClaims.*` in the Jsonnet mapper. Always guard access to - `rawClaims` with `'rawClaims' 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. - - ::: - -```mdx-code-block -import JsonnetWarning from '../../_common/jsonnetwarning.mdx' - - -``` - -2. Encode the Jsonnet snippet with [Base64](https://www.base64encode.org/) or host it under an URL accessible to Ory Network. - - ```shell - cat your-data-mapping.jsonnet | base64 - ``` - -3. Download the Ory Identities config from your project and save it to a file: - - ```shell - ## List all available workspaces - ory list workspaces - - ## List all available projects - ory list projects --workspace - - ## Get config - ory get identity-config --project --workspace --format yaml > identity-config.yaml - ``` - -4. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 - string or provide an 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 an 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 - 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 - ``` - - ::: - -5. Update the Ory Identities configuration using the file you worked with: - - ```shell - ory update identity-config --project --workspace --file identity-config.yaml - ``` - - - -```` - -## 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. - -### Endpoints - -| 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` | - -### 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 | - -## 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 (rawClaims) - -These are accessible via `claims.rawClaims` in the Jsonnet mapper. Availability depends on the user's account level (SOP): - -| Claim | SOP Level | Description | -| -------------------------------- | --------------- | ------------------------------------------------- | -| `claims.rawClaims.uuid` | All | UAE PASS unique user identifier | -| `claims.rawClaims.userType` | All | Account type: `SOP1`, `SOP2`, or `SOP3` | -| `claims.rawClaims.mobile` | All | Verified phone number | -| `claims.rawClaims.email` | All | Verified email | -| `claims.rawClaims.firstnameEN` | All | Given name (English) | -| `claims.rawClaims.lastnameEN` | All | Family name (English) | -| `claims.rawClaims.firstnameAR` | SOP2+ | Given name (Arabic) | -| `claims.rawClaims.lastnameAR` | SOP2+ | Family name (Arabic) | -| `claims.rawClaims.fullnameEN` | SOP2+ | Full name (English) | -| `claims.rawClaims.fullnameAR` | SOP2+ | Full name (Arabic) | -| `claims.rawClaims.nationalityEN` | SOP2+ | Nationality (English) | -| `claims.rawClaims.nationalityAR` | SOP2+ | Nationality (Arabic) | -| `claims.rawClaims.gender` | SOP2+ | Gender | -| `claims.rawClaims.idn` | SOP2+ | Emirates ID number (citizens/residents only) | -| `claims.rawClaims.idType` | SOP2+ | ID type | -| `claims.rawClaims.spuuid` | SOP2+ | SmartPass UUID (SmartPass-verified accounts only) | -| `claims.rawClaims.titleEN` | SOP2+ | Title (English) | -| `claims.rawClaims.titleAR` | SOP2+ | Title (Arabic) | -| `claims.rawClaims.profileType` | SOP3 (Visitors) | `1` (Citizen/Resident) or `2` (Visitor) | -| `claims.rawClaims.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. - -::: - -### Visitor accounts - -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: - -```yaml -scope: - - urn:uae:digitalid:profile:general - - urn:uae:digitalid:profile:general:profileType - - urn:uae:digitalid:profile:general:unifiedId -``` - -You can distinguish visitor profiles from citizen/resident profiles using the `profileType` claim: - -- `profileType = 1` → Citizen or Resident -- `profileType = 2` → Visitor - -## Build and deploy - -The `uaepass` provider requires a custom build of Ory Kratos from the -[fork with UAE PASS support](https://github.com/baytii/kratos). This is necessary because the provider is not yet part of the -upstream Ory Kratos distribution. - -```bash -# Clone the fork -git clone https://github.com/baytii/kratos.git -cd kratos - -# Build the custom Docker image -docker build -t your-registry/kratos:latest-uaepass . - -# Push to your registry -docker push your-registry/kratos:latest-uaepass -``` - -Then reference this image in your `docker-compose.yml` or Kubernetes deployment: - -```yaml -# docker-compose.yml -services: - kratos: - image: your-registry/kratos:latest-uaepass - # ... rest of your config -``` - -## Staging testing - -Follow these steps to test your UAE PASS integration in the staging environment: - -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 - -UAE PASS APIs are publicly accessible — both staging and production endpoints work from overseas. There are currently no charges -for integrating with UAE PASS. - -::: - -## Troubleshooting - -```mdx-code-block -import SocialSigninTroubleshooting from '../_common/social-sign-in-troubleshooting.mdx' - - -``` - -### 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. diff --git a/docs/kratos/social-signin/84_uaepass.mdx b/docs/kratos/social-signin/84_uaepass.mdx index 52a0c2c51..bfdce6756 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 = 'rawClaims' in claims; +local raw = if hasRaw then claims.rawClaims 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.rawClaims.*` in the Jsonnet mapper. Always guard access to +`rawClaims` with `'rawClaims' 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.rawClaims`. + + **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 = 'rawClaims' in claims; + local raw = if hasRaw then claims.rawClaims 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.rawClaims.*` in the Jsonnet mapper. Always guard access to + `rawClaims` with `'rawClaims' 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 an 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 - string or provide a URL to the file. +4. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 + string or provide an 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 an 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 (rawClaims) + +These are accessible via `claims.rawClaims` in the Jsonnet mapper. Availability depends on the user's account level (SOP): + +| Claim | SOP Level | Description | +| -------------------------------- | --------------- | ------------------------------------------------- | +| `claims.rawClaims.uuid` | All | UAE PASS unique user identifier | +| `claims.rawClaims.userType` | All | Account type: `SOP1`, `SOP2`, or `SOP3` | +| `claims.rawClaims.mobile` | All | Verified phone number | +| `claims.rawClaims.email` | All | Verified email | +| `claims.rawClaims.firstnameEN` | All | Given name (English) | +| `claims.rawClaims.lastnameEN` | All | Family name (English) | +| `claims.rawClaims.firstnameAR` | SOP2+ | Given name (Arabic) | +| `claims.rawClaims.lastnameAR` | SOP2+ | Family name (Arabic) | +| `claims.rawClaims.fullnameEN` | SOP2+ | Full name (English) | +| `claims.rawClaims.fullnameAR` | SOP2+ | Full name (Arabic) | +| `claims.rawClaims.nationalityEN` | SOP2+ | Nationality (English) | +| `claims.rawClaims.nationalityAR` | SOP2+ | Nationality (Arabic) | +| `claims.rawClaims.gender` | SOP2+ | Gender | +| `claims.rawClaims.idn` | SOP2+ | Emirates ID number (citizens/residents only) | +| `claims.rawClaims.idType` | SOP2+ | ID type | +| `claims.rawClaims.spuuid` | SOP2+ | SmartPass UUID (SmartPass-verified accounts only) | +| `claims.rawClaims.titleEN` | SOP2+ | Title (English) | +| `claims.rawClaims.titleAR` | SOP2+ | Title (Arabic) | +| `claims.rawClaims.profileType` | SOP3 (Visitors) | `1` (Citizen/Resident) or `2` (Visitor) | +| `claims.rawClaims.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. From 3ad662413407a1a6bbee088caf763c140d70f294 Mon Sep 17 00:00:00 2001 From: George Kutsurua Date: Fri, 13 Mar 2026 18:35:06 +0400 Subject: [PATCH 3/3] docs: fix rawClaims to raw_claims and grammar corrections Apply review feedback: use raw_claims (matching the JSON struct tag in provider.go) instead of rawClaims throughout Jsonnet examples, info blocks, and claims reference tables. Also fix 'an URL' to 'a URL'. --- docs/kratos/social-signin/84_uaepass.mdx | 68 ++++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/docs/kratos/social-signin/84_uaepass.mdx b/docs/kratos/social-signin/84_uaepass.mdx index bfdce6756..f340eec72 100644 --- a/docs/kratos/social-signin/84_uaepass.mdx +++ b/docs/kratos/social-signin/84_uaepass.mdx @@ -67,8 +67,8 @@ local claims = std.extVar('claims'); ```jsonnet local claims = std.extVar('claims'); -local hasRaw = 'rawClaims' in claims; -local raw = if hasRaw then claims.rawClaims else {}; +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(' ', [ @@ -135,8 +135,8 @@ UAE PASS returns different attributes depending on the user's account level (SOP | 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.rawClaims.*` in the Jsonnet mapper. Always guard access to -`rawClaims` with `'rawClaims' in claims` to avoid runtime errors if the field is not populated. +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. @@ -151,7 +151,7 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project 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.rawClaims`. + `std.extVar('claims')`. All UAE PASS-specific attributes are available via `claims.raw_claims`. **Basic mapping** (email and name): @@ -174,8 +174,8 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project ```jsonnet local claims = std.extVar('claims'); - local hasRaw = 'rawClaims' in claims; - local raw = if hasRaw then claims.rawClaims else {}; + 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(' ', [ @@ -242,8 +242,8 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project | 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.rawClaims.*` in the Jsonnet mapper. Always guard access to - `rawClaims` with `'rawClaims' in claims` to avoid runtime errors if the field is not populated. + 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. @@ -254,7 +254,7 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project ``` -2. Encode the Jsonnet snippet with [Base64](https://www.base64encode.org/) or host it under an 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 @@ -274,7 +274,7 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project ``` 4. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 - string or provide an URL to the file. + string or provide a URL to the file. **Staging configuration:** @@ -292,7 +292,7 @@ Follow these steps to add UAE PASS as a social sign-in provider to your project 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 an URL: + # Alternatively, use a URL: # mapper_url: https://storage.googleapis.com/example-example-prd/example-file scope: - urn:uae:digitalid:profile:general @@ -423,32 +423,32 @@ These claims are mapped automatically by the provider and available directly on | `claims.phone_number` | Phone | Mobile number | | `claims.gender` | Gender | Gender | -### UAE PASS-specific claims (rawClaims) +### UAE PASS-specific claims (raw_claims) -These are accessible via `claims.rawClaims` in the Jsonnet mapper. Availability depends on the user's account level (SOP): +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.rawClaims.uuid` | All | UAE PASS unique user identifier | -| `claims.rawClaims.userType` | All | Account type: `SOP1`, `SOP2`, or `SOP3` | -| `claims.rawClaims.mobile` | All | Verified phone number | -| `claims.rawClaims.email` | All | Verified email | -| `claims.rawClaims.firstnameEN` | All | Given name (English) | -| `claims.rawClaims.lastnameEN` | All | Family name (English) | -| `claims.rawClaims.firstnameAR` | SOP2+ | Given name (Arabic) | -| `claims.rawClaims.lastnameAR` | SOP2+ | Family name (Arabic) | -| `claims.rawClaims.fullnameEN` | SOP2+ | Full name (English) | -| `claims.rawClaims.fullnameAR` | SOP2+ | Full name (Arabic) | -| `claims.rawClaims.nationalityEN` | SOP2+ | Nationality (English) | -| `claims.rawClaims.nationalityAR` | SOP2+ | Nationality (Arabic) | -| `claims.rawClaims.gender` | SOP2+ | Gender | -| `claims.rawClaims.idn` | SOP2+ | Emirates ID number (citizens/residents only) | -| `claims.rawClaims.idType` | SOP2+ | ID type | -| `claims.rawClaims.spuuid` | SOP2+ | SmartPass UUID (SmartPass-verified accounts only) | -| `claims.rawClaims.titleEN` | SOP2+ | Title (English) | -| `claims.rawClaims.titleAR` | SOP2+ | Title (Arabic) | -| `claims.rawClaims.profileType` | SOP3 (Visitors) | `1` (Citizen/Resident) or `2` (Visitor) | -| `claims.rawClaims.unifiedId` | SOP3 (Visitors) | Unified user ID | +| `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