Uber: Scaling Verify with Wallet for Identity Verification
Problem + constraints
Uber operates multiple apps and marketplace segments — rides, Eats, rentals — and each has a genuinely different identity-verification need: driver onboarding needs different identity data than an age-gated order, which needs different data again than a car rental. Layered on top, Uber adopted Apple's Verify with Wallet (built on the ISO/IEC 18013-5 mobile driving license standard) as an identity source, which comes with its own constraint: every individual data element Uber wants to request has to be separately approved by Apple through an Entitlement Request tied to its specific intended use case — there's no blanket "give us identity data" grant. So the architecture has to satisfy two pulls at once: support genuinely varied identity-verification needs across business lines, while staying tightly scoped to exactly the data elements each use case was actually approved for, and do it without hard-coding Uber's internal identity model directly against Apple's vendor-specific API shape.
Solution
Uber built a mapping/translation layer between its own internal identity-configuration objects and PassKit's vendor-specific request objects (like PKIdentityIntentToStore), so the rest of Uber's systems reason in terms of Uber's own identity model rather than Apple's API directly. Each business line configures its identity needs at the app level via Entitlement configuration, which the mapping layer translates into the specific PassKit objects for that use case — keeping requests scoped to exactly what's approved rather than over-requesting. On the response side, every payload gets validated twice: server-side checks confirm the returned data elements actually match what was expected for the active use case (catching drift or misuse before it reaches business logic), and separate cryptographic validations confirm the origin and integrity of each data element per the ISO/IEC 18013-5 and Apple standards. Decoupling service logic from the vendor-specific API shape via the mapping layer means Uber's core identity-verification logic doesn't need to change if a future identity source (another wallet, another mDL-compliant vendor) needs to be added — only the mapping layer does.
What to steal
- When integrating an external identity/credential standard with its own strict per-use-case approval model, build a mapping layer that translates your internal model into the vendor's API shape at the boundary — don't let vendor-specific objects leak into your core business logic, or every future vendor integration requires touching everything downstream.
- Validate twice on the response path: structurally (does this data match what we expected for this use case) and cryptographically (is this data element's origin and integrity actually verified) — these catch different failure classes, and collapsing them into one check loses coverage.
- Model "different business lines need different subsets of identity data, each individually approved" as a first-class configuration concern (Entitlement config) rather than special-casing it in code per business line — it's the same shape as any least-privilege / scoped-access problem, just applied to what identity data a given flow is allowed to request and receive.
- A vendor entitlement model that requires per-data-element, per-use-case approval is a forcing function for minimal-necessary-data design — worth treating as a feature to lean into (audit trail of exactly what's approved where) rather than only friction to route around.
Principal Engineer Lens
This case study reads as applied least-privilege at the identity-data layer, and the mapping-layer decoupling is a broadly reusable pattern anywhere a business integrates against an external standard with its own compliance-driven approval model — a very close cousin of what a Fintech or Capital Markets identity-verification system has to do when checking government-issued or mDL-compliant credentials against KYC/AML requirements, since both require strict scoping of exactly which data elements a given flow may request and receive, individually justified and individually auditable. The double-validation pattern (structural match plus cryptographic integrity) is also exactly the kind of design decision that holds up under scrutiny in a security architecture review — "we check it matches AND we check it's genuinely from the source" answers the two different questions a reviewer will actually ask.
Reel Script
Setup: Uber has multiple business lines each needing different identity data, and adopted Apple's Verify with Wallet — which requires every individual data element to be separately approved by Apple for its specific use case, with no blanket grant.
Concept walkthrough: Explain the mapping layer: Uber's internal identity-configuration objects get translated into PassKit-specific request objects at the boundary, driven by per-app Entitlement config, so business logic never talks to Apple's API shape directly. Then explain the double validation on the way back — structural (does this match the expected config for this use case) and cryptographic (is this data element's origin and integrity verified) — as two separate checks catching two separate failure modes.
Real example tie-in: Walk through a concrete flow — a driver-onboarding request configured with one Entitlement, an age-gated order configured with a narrower one — each translated through the same mapping layer into the specific PassKit objects that were actually approved for that use case, then validated twice on response before the data reaches Uber's business logic.
Tradeoffs & alternatives: Contrast with calling PassKit's API directly from each business line's code — faster to ship initially, but it means every future identity-source integration (a second wallet vendor, a different mDL-compliant provider) requires touching every call site instead of just the mapping layer. The upfront cost of the abstraction pays for itself the moment a second identity source needs to be added.
Principal Engineer takeaway: Vendor and compliance-driven approval models that force per-use-case scoping aren't just friction to build around — treat them as a forcing function toward minimal-necessary-data design, and isolate the vendor-specific shape behind a mapping layer so your core identity logic stays stable as vendors and standards change underneath it.
Related
Sources: