Bilko Mobile Entra Auth Bridge Spec
Bilko Mobile — Entra External ID Auth Bridge Spec
Status: Phase 0 backend prerequisite
Date: 2026-06-04
Related:docs/architecture/ADR-037-BILKO-MOBILE-NATIVE-ENTRA-AUTH.md,docs/mobile/MOBILE-IMPL-SPEC-PHASE1.md
Purpose
Enable Bilko native mobile login for iPhone and Samsung/Android via Microsoft Entra External ID without relying on browser httpOnly refresh cookies.
The existing web cookie flow must remain intact until a separate web migration is explicitly approved.
Target Flow
- Mobile app starts Microsoft Entra External ID login using OIDC Authorization Code + PKCE (
expo-auth-session). - Mobile receives an Entra ID token / auth result.
- Mobile calls Bilko backend auth bridge with the Entra token.
- Backend validates Entra token issuer, audience, expiry, signature, and required claims using Entra JWKS.
- Backend maps the external identity to Bilko
user,organization, and role. - Backend issues Bilko API/session tokens suitable for React Native secure storage.
- Mobile stores token/session material only in
expo-secure-store.
Required Endpoints
POST /api/v1/auth/entra/session
Creates or resumes a Bilko session from a validated Entra identity.
Request:
{
"idToken": "<entra-id-token>",
"client": "mobile",
"device": {
"platform": "ios|android",
"appVersion": "1.0.0"
}
}
Response:
{
"user": {
"id": "uuid",
"email": "[email protected]",
"fullName": "Full Name",
"role": "owner|admin|accountant|viewer"
},
"organization": {
"id": "uuid",
"name": "Company Name",
"country": "HR|RS|BA",
"baseCurrency": "EUR|RSD|BAM",
"language": "hr|sr-Latn|sr-Cyrl|bs|en"
},
"tokens": {
"accessToken": "<bilko-api-jwt>",
"refreshToken": "<bilko-mobile-refresh-token>",
"expiresIn": 900
}
}
Rules:
- Do not set or require browser cookies for
client: mobile. - Do not accept unsigned/unverified JWTs.
- Do not trust email alone as identity key; store Entra issuer + subject/object ID mapping.
- If a matching Bilko user/org cannot be resolved, return an explicit onboarding/not-authorized error; do not silently create an organization.
POST /api/v1/auth/mobile/refresh
Refreshes Bilko API access token from a mobile refresh token stored in Keychain/Keystore.
Request:
{
"refreshToken": "<bilko-mobile-refresh-token>"
}
Response:
{
"accessToken": "<bilko-api-jwt>",
"refreshToken": "<rotated-refresh-token>",
"expiresIn": 900
}
Rules:
- Rotate refresh tokens.
- Reject reused/revoked refresh tokens.
- Bind refresh token to user/session/device metadata where feasible.
- Existing
POST /api/v1/auth/refreshcookie flow may remain for web.
POST /api/v1/auth/logout
For mobile, revoke the current Bilko mobile refresh/session token and return success. Entra hosted session logout can be added later if required.
Data Model Requirements
At minimum, persist:
- Entra issuer (
iss). - Entra subject/object ID (
sub/oid, exact claim depends on tenant config). - Bilko user ID.
- Organization membership and role.
- Mobile refresh token hash, expiry, rotation family/session ID, device metadata, revoked timestamp.
Never store plaintext refresh tokens.
Configuration Requirements
Environment/config values:
ENTRA_EXTERNAL_ID_ISSUERENTRA_EXTERNAL_ID_AUDIENCEENTRA_EXTERNAL_ID_JWKS_URLENTRA_EXTERNAL_ID_TENANT_IDor equivalent tenant/domain identifier- Allowed mobile redirect URIs for Expo dev/staging/production
No secrets should be committed to the repo.
Acceptance Criteria
Phase 0 is complete when:
- A real Entra test user can log in from an Expo iOS simulator build and receive Bilko
user,organization, and tokens. - The same flow works on Android emulator.
- Refresh works without browser cookies.
- Invalid issuer/audience/signature/expired token tests fail closed.
- A user with no Bilko org mapping receives a controlled not-authorized/onboarding response.
- Backend tests cover token validation, org/role mapping, refresh rotation, and logout/revocation.
- Web cookie-based login still passes existing tests.
Security Review Items
- Confirm Entra External ID tenant policy and MFA/passwordless settings.
- Confirm JWKS caching and key rotation handling.
- Confirm token TTLs and refresh-token max lifetime.
- Confirm logging does not include tokens or PII-heavy claims.
- Confirm Sentry/telemetry scrubbing for auth errors.
No comments to display
No comments to display