|
| 1 | +--- |
| 2 | +id: uaepass |
| 3 | +title: Add UAE PASS as a social sign-in provider in Ory |
| 4 | +sidebar_label: UAE PASS |
| 5 | +--- |
| 6 | + |
| 7 | +# UAE PASS |
| 8 | + |
| 9 | +:::note |
| 10 | + |
| 11 | +To add UAE PASS as a social sign-in provider, you need a UAE PASS integration account. Visit |
| 12 | +[UAE PASS](https://docs.uaepass.ae) to register your application. For testing, use the staging credentials |
| 13 | +`sandbox_stage` / `sandbox_stage`. |
| 14 | + |
| 15 | +::: |
| 16 | + |
| 17 | +````mdx-code-block |
| 18 | +import Tabs from '@theme/Tabs'; |
| 19 | +import TabItem from '@theme/TabItem'; |
| 20 | +
|
| 21 | +<Tabs> |
| 22 | +<TabItem value="cli" label="Ory CLI / Self-Hosted" default> |
| 23 | +
|
| 24 | +Follow these steps to add UAE PASS as a social sign-in provider to your project using the Ory CLI or self-hosted Kratos: |
| 25 | +
|
| 26 | +1. Create a Jsonnet code snippet to map the desired claims to the Ory Identity schema. |
| 27 | +
|
| 28 | + UAE PASS doesn't return an `id_token`. Ory sends requests to UAE PASS's userinfo API and adds the user info to |
| 29 | + `std.extVar('claims')`. All UAE PASS-specific attributes are available via `claims.rawClaims`. |
| 30 | +
|
| 31 | + **Basic mapping** (email and name): |
| 32 | +
|
| 33 | + ```jsonnet |
| 34 | + local claims = std.extVar('claims'); |
| 35 | + { |
| 36 | + identity: { |
| 37 | + traits: { |
| 38 | + [if 'email' in claims then 'email' else null]: claims.email, |
| 39 | + name: { |
| 40 | + first: claims.given_name, |
| 41 | + last: claims.family_name, |
| 42 | + }, |
| 43 | + }, |
| 44 | + }, |
| 45 | + } |
| 46 | + ``` |
| 47 | +
|
| 48 | + **Full mapping** (with UAE PASS metadata): |
| 49 | +
|
| 50 | + ```jsonnet |
| 51 | + local claims = std.extVar('claims'); |
| 52 | + local raw = claims.rawClaims; |
| 53 | + { |
| 54 | + identity: { |
| 55 | + traits: { |
| 56 | + [if 'email' in claims then 'email' else null]: claims.email, |
| 57 | + [if 'phone_number' in claims then 'phone' else null]: claims.phone_number, |
| 58 | + name: { |
| 59 | + first: claims.given_name, |
| 60 | + last: claims.family_name, |
| 61 | + }, |
| 62 | + }, |
| 63 | + metadata_public: { |
| 64 | + uaepass: { |
| 65 | + user_type: raw.userType, |
| 66 | + [if 'idn' in raw then 'emirates_id' else null]: raw.idn, |
| 67 | + [if 'nationalityEN' in raw then 'nationality' else null]: raw.nationalityEN, |
| 68 | + [if 'gender' in raw then 'gender' else null]: raw.gender, |
| 69 | + [if 'fullnameAR' in raw then 'fullname_ar' else null]: raw.fullnameAR, |
| 70 | + }, |
| 71 | + }, |
| 72 | + }, |
| 73 | + } |
| 74 | + ``` |
| 75 | +
|
| 76 | + :::info |
| 77 | +
|
| 78 | + UAE PASS returns different attributes depending on the user's account level (SOP): |
| 79 | +
|
| 80 | + | Level | Name | Available Attributes | |
| 81 | + |-------|-------------|---------------------| |
| 82 | + | SOP1 | Basic | uuid, email, mobile, firstnameEN, lastnameEN, userType | |
| 83 | + | SOP2 | Advanced | All SOP1 + full names (EN/AR), nationality, gender, idn, idType | |
| 84 | + | SOP3 | Qualified | All SOP2 + titleEN/AR, profileType, unifiedId | |
| 85 | +
|
| 86 | + All raw attributes are accessible via `claims.rawClaims.*` in the Jsonnet mapper. |
| 87 | +
|
| 88 | + ::: |
| 89 | +
|
| 90 | +```mdx-code-block |
| 91 | +import JsonnetWarning from '../../_common/jsonnetwarning.mdx' |
| 92 | +
|
| 93 | +<JsonnetWarning format="Jsonnet code snippets" use="data mapping" /> |
| 94 | +``` |
| 95 | +
|
| 96 | +2. Encode the Jsonnet snippet with [Base64](https://www.base64encode.org/) or host it under an URL accessible to Ory Network. |
| 97 | +
|
| 98 | + ```shell |
| 99 | + cat your-data-mapping.jsonnet | base64 |
| 100 | + ``` |
| 101 | +
|
| 102 | +3. Download the Ory Identities config from your project and save it to a file: |
| 103 | +
|
| 104 | + ```shell |
| 105 | + ## List all available workspaces |
| 106 | + ory list workspaces |
| 107 | +
|
| 108 | + ## List all available projects |
| 109 | + ory list projects --workspace <workspace-id> |
| 110 | +
|
| 111 | + ## Get config |
| 112 | + ory get identity-config --project <project-id> --workspace <workspace-id> --format yaml > identity-config.yaml |
| 113 | + ``` |
| 114 | +
|
| 115 | +4. Add the social sign-in provider configuration to the downloaded config. Add the Jsonnet snippet with mappings as a Base64 |
| 116 | + string or provide an URL to the file. |
| 117 | +
|
| 118 | + **Staging configuration:** |
| 119 | +
|
| 120 | + ```yaml |
| 121 | + selfservice: |
| 122 | + methods: |
| 123 | + oidc: |
| 124 | + config: |
| 125 | + providers: |
| 126 | + - id: uaepass # this is `<provider-id>` in the Authorization callback URL. DO NOT CHANGE IT ONCE SET! |
| 127 | + provider: uaepass |
| 128 | + client_id: sandbox_stage |
| 129 | + client_secret: sandbox_stage |
| 130 | + auth_url: https://stg-id.uaepass.ae/idshub/authorize |
| 131 | + token_url: https://stg-id.uaepass.ae/idshub/token |
| 132 | + issuer_url: https://stg-id.uaepass.ae/idshub |
| 133 | + mapper_url: "base64://{YOUR_BASE64_ENCODED_JSONNET_HERE}" |
| 134 | + # Alternatively, use an URL: |
| 135 | + # mapper_url: https://storage.googleapis.com/example-example-prd/example-file |
| 136 | + scope: |
| 137 | + - urn:uae:digitalid:profile:general |
| 138 | + enabled: true |
| 139 | + ``` |
| 140 | +
|
| 141 | + **Production configuration:** |
| 142 | +
|
| 143 | + ```yaml |
| 144 | + selfservice: |
| 145 | + methods: |
| 146 | + oidc: |
| 147 | + config: |
| 148 | + providers: |
| 149 | + - id: uaepass |
| 150 | + provider: uaepass |
| 151 | + client_id: .... # Replace with your UAE PASS client ID |
| 152 | + client_secret: .... # Replace with your UAE PASS client secret |
| 153 | + auth_url: https://id.uaepass.ae/idshub/authorize |
| 154 | + token_url: https://id.uaepass.ae/idshub/token |
| 155 | + issuer_url: https://id.uaepass.ae/idshub |
| 156 | + mapper_url: "base64://{YOUR_BASE64_ENCODED_JSONNET_HERE}" |
| 157 | + scope: |
| 158 | + - urn:uae:digitalid:profile:general |
| 159 | + enabled: true |
| 160 | + ``` |
| 161 | +
|
| 162 | + :::tip |
| 163 | +
|
| 164 | + For visitor integration, add extra scopes to retrieve `profileType` and `unifiedId`: |
| 165 | +
|
| 166 | + ```yaml |
| 167 | + scope: |
| 168 | + - urn:uae:digitalid:profile:general |
| 169 | + - urn:uae:digitalid:profile:general:profileType |
| 170 | + - urn:uae:digitalid:profile:general:unifiedId |
| 171 | + ``` |
| 172 | +
|
| 173 | + ::: |
| 174 | +
|
| 175 | +5. Update the Ory Identities configuration using the file you worked with: |
| 176 | +
|
| 177 | + ```shell |
| 178 | + ory update identity-config --project <project-id> --workspace <workspace-id> --file identity-config.yaml |
| 179 | + ``` |
| 180 | +
|
| 181 | +</TabItem> |
| 182 | +</Tabs> |
| 183 | +```` |
| 184 | + |
| 185 | +## Configuration reference |
| 186 | + |
| 187 | +The `uaepass` provider handles the following UAE PASS requirements automatically: |
| 188 | + |
| 189 | +- **No OIDC discovery** — UAE PASS doesn't expose `.well-known/openid-configuration`. Endpoints are configured directly. |
| 190 | +- **No `openid` scope** — UAE PASS doesn't support the standard `openid` scope. Use `urn:uae:digitalid:profile:general`. |
| 191 | +- **`acr_values` injection** — The required `urn:safelayer:tws:policies:authentication:level:low` parameter is added automatically. |
| 192 | +- **`client_secret_basic` auth** — The token endpoint uses HTTP Basic authentication as required by UAE PASS. |
| 193 | +- **Userinfo-based claims** — UAE PASS doesn't return ID tokens. Claims are fetched from the userinfo endpoint. |
| 194 | + |
| 195 | +### Endpoints |
| 196 | + |
| 197 | +| Environment | Authorize | Token | Userinfo | Logout | |
| 198 | +|-------------|-----------|-------|----------|--------| |
| 199 | +| 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` | |
| 200 | +| 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` | |
| 201 | + |
| 202 | +### Configuration fields |
| 203 | + |
| 204 | +| Field | Required | Description | |
| 205 | +|-------|----------|-------------| |
| 206 | +| `provider` | Yes | Must be `uaepass` | |
| 207 | +| `client_id` | Yes | Your UAE PASS client ID (use `sandbox_stage` for staging) | |
| 208 | +| `client_secret` | Yes | Your UAE PASS client secret (use `sandbox_stage` for staging) | |
| 209 | +| `auth_url` | No | Authorization endpoint. Defaults to staging if omitted | |
| 210 | +| `token_url` | No | Token endpoint. Defaults to staging if omitted | |
| 211 | +| `issuer_url` | No | Base URL for deriving the userinfo endpoint (`{issuer_url}/userinfo`). Defaults to staging if omitted | |
| 212 | +| `scope` | Yes | Must include `urn:uae:digitalid:profile:general` | |
| 213 | +| `mapper_url` | Yes | Path or Base64-encoded Jsonnet mapper | |
| 214 | + |
| 215 | +## Available claims |
| 216 | + |
| 217 | +UAE PASS doesn't return an `id_token`. Ory sends requests to UAE PASS's userinfo API and adds the user info to |
| 218 | +`std.extVar('claims')`. |
| 219 | + |
| 220 | +### Standard claims |
| 221 | + |
| 222 | +These claims are mapped automatically by the provider and available directly on the `claims` object: |
| 223 | + |
| 224 | +| Claim | Field | Description | |
| 225 | +|-------|-------|-------------| |
| 226 | +| `claims.sub` | Subject | UUID (preferred) or sub identifier | |
| 227 | +| `claims.given_name` | Given Name | `firstnameEN` from UAE PASS | |
| 228 | +| `claims.family_name` | Family Name | `lastnameEN` from UAE PASS | |
| 229 | +| `claims.name` | Full Name | `fullnameEN` from UAE PASS | |
| 230 | +| `claims.email` | Email | Verified email | |
| 231 | +| `claims.phone_number` | Phone | Mobile number | |
| 232 | +| `claims.gender` | Gender | Gender | |
| 233 | + |
| 234 | +### UAE PASS-specific claims (rawClaims) |
| 235 | + |
| 236 | +These are accessible via `claims.rawClaims` in the Jsonnet mapper. Availability depends on the user's account level |
| 237 | +(SOP): |
| 238 | + |
| 239 | +| Claim | SOP Level | Description | |
| 240 | +|-------|-----------|-------------| |
| 241 | +| `claims.rawClaims.uuid` | All | UAE PASS unique user identifier | |
| 242 | +| `claims.rawClaims.userType` | All | Account type: `SOP1`, `SOP2`, or `SOP3` | |
| 243 | +| `claims.rawClaims.mobile` | All | Verified phone number | |
| 244 | +| `claims.rawClaims.email` | All | Verified email | |
| 245 | +| `claims.rawClaims.firstnameEN` | All | Given name (English) | |
| 246 | +| `claims.rawClaims.lastnameEN` | All | Family name (English) | |
| 247 | +| `claims.rawClaims.firstnameAR` | SOP2+ | Given name (Arabic) | |
| 248 | +| `claims.rawClaims.lastnameAR` | SOP2+ | Family name (Arabic) | |
| 249 | +| `claims.rawClaims.fullnameEN` | SOP2+ | Full name (English) | |
| 250 | +| `claims.rawClaims.fullnameAR` | SOP2+ | Full name (Arabic) | |
| 251 | +| `claims.rawClaims.nationalityEN` | SOP2+ | Nationality (English) | |
| 252 | +| `claims.rawClaims.nationalityAR` | SOP2+ | Nationality (Arabic) | |
| 253 | +| `claims.rawClaims.gender` | SOP2+ | Gender | |
| 254 | +| `claims.rawClaims.idn` | SOP2+ | Emirates ID number (citizens/residents only) | |
| 255 | +| `claims.rawClaims.idType` | SOP2+ | ID type | |
| 256 | +| `claims.rawClaims.spuuid` | SOP2+ | SmartPass UUID (SmartPass-verified accounts only) | |
| 257 | +| `claims.rawClaims.titleEN` | SOP2+ | Title (English) | |
| 258 | +| `claims.rawClaims.titleAR` | SOP2+ | Title (Arabic) | |
| 259 | +| `claims.rawClaims.profileType` | SOP3 (Visitors) | `1` (Citizen/Resident) or `2` (Visitor) | |
| 260 | +| `claims.rawClaims.unifiedId` | SOP3 (Visitors) | Unified user ID | |
| 261 | + |
| 262 | +:::caution |
| 263 | + |
| 264 | +The `idn` (Emirates ID) attribute is **not returned for Visitor profiles**. It is only available for Citizens and |
| 265 | +Residents with SOP2 or SOP3 accounts. |
| 266 | + |
| 267 | +::: |
| 268 | + |
| 269 | +## User account types (SOP levels) |
| 270 | + |
| 271 | +UAE PASS supports three account levels, known as Standard Operating Procedures (SOPs). The account level determines |
| 272 | +which attributes are returned in the userinfo response. |
| 273 | + |
| 274 | +| Level | Name | Verification Method | Available Attributes | |
| 275 | +|-------|------|---------------------|----------------------| |
| 276 | +| SOP1 | Basic | Email + Mobile OTP only. Account is unverified. | uuid, email, mobile, firstnameEN, lastnameEN, userType | |
| 277 | +| 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 | |
| 278 | +| SOP3 | Qualified | Emirates ID + Biometrics (face or fingerprint). Account is verified. | All SOP2 + profileType, unifiedId | |
| 279 | + |
| 280 | +:::info |
| 281 | + |
| 282 | +SOP2 and SOP3 accounts have access to digital signature capabilities. SOP1 accounts only support authentication — they |
| 283 | +cannot use digital signature or data/document sharing features. |
| 284 | + |
| 285 | +::: |
| 286 | + |
| 287 | +### Visitor accounts |
| 288 | + |
| 289 | +Visitors (non-Citizens/non-Residents) have a different attribute set. Visitors only support SOP1 and SOP3 levels. |
| 290 | +To retrieve visitor-specific attributes, add extra scopes to your configuration: |
| 291 | + |
| 292 | +```yaml |
| 293 | +scope: |
| 294 | + - urn:uae:digitalid:profile:general |
| 295 | + - urn:uae:digitalid:profile:general:profileType |
| 296 | + - urn:uae:digitalid:profile:general:unifiedId |
| 297 | +``` |
| 298 | +
|
| 299 | +You can distinguish visitor profiles from citizen/resident profiles using the `profileType` claim: |
| 300 | +- `profileType = 1` → Citizen or Resident |
| 301 | +- `profileType = 2` → Visitor |
| 302 | + |
| 303 | +## Build and deploy |
| 304 | + |
| 305 | +The `uaepass` provider requires a custom build of Ory Kratos from the |
| 306 | +[fork with UAE PASS support](https://github.com/baytii/kratos). This is necessary because the provider is not yet part |
| 307 | +of the upstream Ory Kratos distribution. |
| 308 | + |
| 309 | +```bash |
| 310 | +# Clone the fork |
| 311 | +git clone https://github.com/baytii/kratos.git |
| 312 | +cd kratos |
| 313 | +
|
| 314 | +# Build the custom Docker image |
| 315 | +docker build -t your-registry/kratos:latest-uaepass . |
| 316 | +
|
| 317 | +# Push to your registry |
| 318 | +docker push your-registry/kratos:latest-uaepass |
| 319 | +``` |
| 320 | + |
| 321 | +Then reference this image in your `docker-compose.yml` or Kubernetes deployment: |
| 322 | + |
| 323 | +```yaml |
| 324 | +# docker-compose.yml |
| 325 | +services: |
| 326 | + kratos: |
| 327 | + image: your-registry/kratos:latest-uaepass |
| 328 | + # ... rest of your config |
| 329 | +``` |
| 330 | + |
| 331 | +## Staging testing |
| 332 | + |
| 333 | +Follow these steps to test your UAE PASS integration in the staging environment: |
| 334 | + |
| 335 | +1. **Create a staging account**: Set up a UAE PASS staging account at |
| 336 | + [docs.uaepass.ae](https://docs.uaepass.ae/start-test-environment-implementation/create-uaepass-user). Staging |
| 337 | + accounts can be created from any location — there are no geographic restrictions. |
| 338 | +2. **Use staging credentials**: `client_id: sandbox_stage`, `client_secret: sandbox_stage`. |
| 339 | +3. **Upgrade your account** (optional): The staging account starts as SOP1 (basic). To test SOP2/SOP3 attributes, |
| 340 | + upgrade via the |
| 341 | + [self-care portal](https://docs.uaepass.ae/quick-start-guide-uae-pass-staging-environment/upgrade-staging-uae-pass-account). |
| 342 | +4. **Run a POC**: Follow the |
| 343 | + [POC guide](https://docs.uaepass.ae/quick-start-guide-uae-pass-staging-environment/conduct-a-poc-with-uae-pass-authentication) |
| 344 | + to verify the authentication flow end-to-end. |
| 345 | + |
| 346 | +:::note |
| 347 | + |
| 348 | +UAE PASS APIs are publicly accessible — both staging and production endpoints work from overseas. There are currently no |
| 349 | +charges for integrating with UAE PASS. |
| 350 | + |
| 351 | +::: |
| 352 | + |
| 353 | +## Troubleshooting |
| 354 | + |
| 355 | +```mdx-code-block |
| 356 | +import SocialSigninTroubleshooting from '../_common/social-sign-in-troubleshooting.mdx' |
| 357 | +
|
| 358 | +<SocialSigninTroubleshooting /> |
| 359 | +``` |
| 360 | + |
| 361 | +### UAE PASS-specific issues |
| 362 | + |
| 363 | +- **No attributes returned**: Check the user's SOP level. SOP1 accounts return only basic attributes (uuid, email, |
| 364 | + mobile, firstnameEN, lastnameEN). Upgrade the staging account to SOP3 for full attribute testing. |
| 365 | +- **Missing `idn` for visitors**: The Emirates ID (`idn`) attribute is not returned for Visitor profiles. This is |
| 366 | + expected behavior. |
| 367 | +- **Logout redirect issues**: UAE PASS only accepts a `state` parameter in the logout URL. To pass additional |
| 368 | + parameters, Base64-encode them into the `state` parameter: |
| 369 | + ``` |
| 370 | + https://stg-id.uaepass.ae/idshub/logout?redirect_uri=https://your-app.com/logout&state={base64_encoded_query_string} |
| 371 | + ``` |
| 372 | + |
| 373 | +### Credits |
| 374 | + |
| 375 | +This provider was developed by [GBYTE TECH](https://gbyte.tech/) and is available under the Apache 2.0 license. |
0 commit comments