From b3bd53f7e758afcbb66b7c76287ba70575b97421 Mon Sep 17 00:00:00 2001 From: George Kutsurua Date: Mon, 23 Feb 2026 18:52:26 +0400 Subject: [PATCH] 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",