3. Identity Domains & Access Control¶
3.1 Trust Boundaries¶
| Actor | Link trusts them to... |
|---|---|
| Integrator | Correctly identify their users before enrollment (when providing own user_id) |
| Link Device | Capture authentic palm templates |
| Verification Server | Securely store templates and match accurately |
| Product Backends | Honor the platform's authorize decision and run their own business logic (charge wallet, grant access) — §10 |
| Google/Apple | Provide valid ID tokens for social login |
| KYC Providers | Verify user identity (Nafath, Onfido, etc.) |
3.2 Identity Domains¶
The platform has two distinct identity domains. These are separate systems with separate storage — they never overlap.
| Domain | Who | Auth | Storage | Accesses |
|---|---|---|---|---|
| Console users (manage the platform) | Platform Admin, Tenant Admin, Tenant Operator | Email/password + MFA, console session | console_users table |
Web Console only |
| Managed identities (managed BY the platform) | End Users | OTP/password/social → User JWT | users table |
Auth endpoints only (login, password change, token revoke). All other operations go through the integrator's backend. |
Additionally, two non-human actors interact with the platform:
| Actor | Auth | Storage | Accesses |
|---|---|---|---|
| Integrator Backend | OAuth client_credentials |
oauth_clients table |
All tenant-scoped REST APIs (user CRUD, KYC, enrollment, verification, consent) |
| Device (personal scanner / pos / gate / kiosk) | mTLS / device certificate | devices table |
Challenge polling (personal scanner) or device-initiated transactions / signup / enroll (pos/gate/kiosk) — §9, §10 |
Key principle: End users never access the Web Console or call management APIs directly. They interact with their integrator's application (mobile app, kiosk, POS), which calls the Identity Platform on their behalf using client_credentials. The only endpoints an end user calls directly are the auth endpoints for login, password change, and token revocation.
3.3 Console Roles¶
The platform separates authentication (who you are — Section 6) from authorization (what you can do). This section defines the role-based access control (RBAC) model that governs who can manage platform resources, tenant configuration, and user data.
| Role | Scope | Description |
|---|---|---|
| Platform Admin | All tenants | Link operations team. Creates/suspends tenants, manages platform configuration, views cross-tenant metrics. |
| Tenant Admin | Single tenant | Integrator's administrator. Full control within their tenant: settings, OAuth clients, devices, users, audit logs. |
| Tenant Operator | Single tenant | Day-to-day support staff. Views users, KYC pipeline, audit logs, dashboard. Cannot modify tenant configuration or manage OAuth clients. Read-heavy role. |
Why Tenant Operator? Saudi regulated industries (SAMA requirements) mandate least-privilege access. Support staff need to view user data for troubleshooting without the ability to change configuration. Audit trails can distinguish "who changed settings" from "who viewed data."
3.4 Console Permission Matrix¶
| Permission | Platform Admin | Tenant Admin | Tenant Operator |
|---|---|---|---|
| Create / suspend / delete tenants | Yes | — | — |
| View all tenants | Yes | — | — |
| Configure tenant settings | Yes | Own tenant | — |
| Manage OAuth clients | Yes | Own tenant | — |
| Manage devices / scanners | Yes | Own tenant | View |
| Manage platform SSL certs (server cert + platform CA, incl. first-run setup) | Yes | — | — |
| Configure device cert policy | Yes | — | — |
| Configure webhooks | Yes | Own tenant | — |
| View users | Yes | Own tenant | Own tenant |
| Manage users (suspend / delete) | Yes | Own tenant | — |
| View audit logs | Yes | Own tenant | Own tenant |
| View KYC pipeline | Yes | Own tenant | Own tenant |
| View consent records | Yes | Own tenant | Own tenant |
| View dashboard / analytics | Yes | Own tenant | Own tenant |
Notes: - "Own tenant" means within the tenant the admin/operator belongs to. - Platform Admin operates through a platform-level console or superadmin mode, not through a tenant-scoped view.
3.5 End User Access¶
End users authenticate directly with the Identity Platform for login only. All other operations go through their integrator's backend. End users cannot access the Web Console, management APIs, or any endpoint requiring client_credentials. See Section 14.1 for the complete endpoint reference.
3.6 Role Assignment¶
| Role | How Assigned | Authentication | Storage |
|---|---|---|---|
| Platform Admin | Assigned internally by Link ops | Web Console (email/password + MFA) | console_users table with role: "platform_admin" |
| Tenant Admin | Created during tenant provisioning (see Section 4) | Web Console (email/password + MFA) | console_users table with tenant_id + role: "tenant_admin" |
| Tenant Operator | Created by Tenant Admin via Web Console | Web Console (email/password) | console_users table with tenant_id + role: "tenant_operator" |
| Integrator Backend | Represented by OAuth clients (see Section 6.4) | client_credentials grant | oauth_clients table with tenant_id |
| End User | Created via signup or POST /v1/users |
OTP / password / social → User JWT | users table with tenant_id |
First Platform Admin (initial deploy). On a fresh install with no platform_admin row in console_users, the backend seeds one from two env vars on first boot:
PLATFORM_ADMIN_EMAIL— the admin's email address (required)PLATFORM_ADMIN_INITIAL_PASSWORD— the admin's initial password (optional; if absent, the backend generates a random one and prints it to stdout once)
The seeded admin is created with must_change_password=true and is forced to set a new password on first login. The env vars are read only when no Platform Admin exists — subsequent boots ignore them, so they may safely remain in the deployment config or be removed entirely after first run. This is the standard self-hosted-vendor pattern (compare GitLab's GITLAB_ROOT_PASSWORD, Grafana's GF_SECURITY_ADMIN_PASSWORD). There is no separate "bootstrap" admin role.
3.7 API Authorization¶
How the platform determines the caller's identity and enforces access:
| Auth Mechanism | Role Determined | Tenant Scope |
|---|---|---|
OAuth client_credentials token |
Integrator Backend | tenant_id from client registry |
| User JWT (access token) | End User | user_id + tenant_id from token claims |
| Web Console session | Platform Admin, Tenant Admin, or Tenant Operator | role + tenant_id from session |
| mTLS device certificate | Device (not a role — see Section 9) | device_id + tenant_id from certificate |
3.8 Verification Semantics¶
The platform confirms:
"The palm scanned matches the palm enrolled for user_id X at timestamp T"
It returns metadata (confidence score, timestamp) — not a signed proof. The platform does not make identity claims; for identity proofing, KYC verification is required.
3.9 Security Model¶
| Attack Vector | Mitigation |
|---|---|
| Token stolen | Short-lived access tokens (24h), refresh tokens revocable |
| Man-in-middle | TLS for all communication |
| Template theft | Templates stored in Verification Server, not exposed via API |
| Presentation attack | Palm vein technology inherently requires live blood flow |
| Password breach | bcrypt hashing, breach detection |
| KYC fraud | Government-issued ID verification via trusted providers |
| Scanner identity spoofing | Per-device mTLS client cert with private key bound to Android StrongBox (non-exportable). Cert SAN URI carries device_id/tenant_id and is verified on every request — see §9.2.1. |
| Stolen device cert | Revoke via DELETE /v1/devices/{id} → fingerprint goes into denylist; TLS handshake rejects on next connection. Device must re-pair from scratch. |
| Platform CA private key compromise | Regenerate CA via POST /v1/admin/ssl/ca-cert/regenerate (destructive). All device certs invalidated; scanners must re-pair. Audit event platform_ca_regenerated is high-severity. |
| Replay / impersonation during pairing | 9-char pairing code (~47 bits entropy), 5-min TTL, single-use via atomic SQL, rate-limited per source IP. CSR proof-of-possession ensures only the key holder can use the code (§9.2.1). |
| Cross-tenant access via stolen cert | SAN URI binds the cert to a specific tenant_id; middleware uses this for tenant scope. A device cert from tenant A cannot access tenant B endpoints. |