20 — Guest Mobile Key Specification
Surface: Consumer Mobile + Staff Mobile Companion (iOS + Android — React Native) Phase: R3 (BLE/Wallet) — R2 for QR/PIN fallback flows Audience: Guests and staff who need to use a mobile phone as a room key Feature flags:
mobile-key-ble(R3),mobile-key-wallet(R3) Cross-reference:../../09-lock-and-key-integration.md
1. Overview
Guest Mobile Key allows a guest (or staff member) to use their smartphone as a room key credential, eliminating the need for a physical RFID card. The experience is modeled after Marriott's Digital Key, Hilton's Digital Key Share, and Hyatt's World of Hyatt Mobile Key.
Key issuance methods by phase:
| Method | Phase | Tenant requirement | Guest requirement |
|---|---|---|---|
| QR code / PIN code (static, displayed in-app) | R2 | Any lock with PIN/QR scanner | None (no BLE, no Wallet) |
| NFC tap (Android) | R2 | NFC-capable lock; Android NFC reader app | Android with NFC |
| BLE credential (TTLock BLE, Dormakaba) | R3 | BLE-capable lock vendor SDK | mobile-key-ble flag on; Bluetooth permission |
| Apple Wallet key pass | R3 | Apple-approved lock vendor (Assa Abloy, NXP) | iPhone with iOS 16+ |
| Google Wallet key pass | R3 | Google-approved vendor | Android with Google Wallet |
2. User flow (QR / PIN — R2)
Booking confirmed
↓
Guest receives EM-01 confirmation email with "Get room key" CTA
↓
Guest taps CTA → opens app → authenticates (biometric or OTP)
↓
"Your key is ready" screen
[Key card visual — animated, branded to tenant]
[Room number, check-in/check-out dates]
[QR code — tap to enlarge, works on lock QR reader]
[PIN code — displayed if lock supports PIN]
[Share key (R3+)]
↓
Guest approaches lock → scans QR / enters PIN / taps NFC
↓
Door opens
2.1 Key screen anatomy
[Tenant logo]
[Property name]
[Room] 201 — Standard Double
[Animated key card visual — tenant-branded]
[QR code inside card]
or [PIN: 1234]
Valid: 1 May 2026 — 3 May 2026
[Tap to enlarge QR]
[Copy PIN]
[Add to Wallet (R3)]
Offline: The QR code and PIN are stored encrypted in expo-secure-store at key issuance. Displayed offline with a "Last updated: <timestamp>" note.
Security: QR code payload is a signed JWT (kid + iss + sub + iat + exp) generated by lock-integration-service. The lock vendor API validates the JWT offline (the lock has the public key embedded).
3. User flow (BLE — R3)
Guest opens app → taps "Unlock my room"
↓
App starts BLE scan (react-native-ble-plx)
↓
Lock device discovered (matched by lock UUID in credential)
↓
BLE connect → authenticate with embedded credential
↓
Lock actuates (unlock animation in app + haptic feedback)
Permission: ACCESS_FINE_LOCATION (Android, required for BLE scan in Android < 12) + BLUETOOTH_SCAN + BLUETOOTH_CONNECT (Android 12+). iOS: NSBluetoothAlwaysUsageDescription. Request at first "Unlock" tap, not at install.
Background BLE: Lock detection in background is NOT enabled (too battery-intensive + complex for R3). Guest must open the app and tap "Unlock".
Error handling:
- Lock not found: show C3 ER-05 modal "Could not find lock — are you near your room? Tap to try again."
- BLE turned off: show system prompt to enable Bluetooth.
- Credential expired:
MELMASTOON.LOCK.CREDENTIAL_EXPIRED→ fetch fresh credential from BFF.
4. Apple Wallet / Google Wallet (R3)
Apple Wallet:
- Lock vendor (e.g., Assa Abloy Incedo) provides Apple Passkit PKpass.
lock-integration-servicegenerates PKpass and signs with Apple certificate.- App receives PKpass download URL.
expo-passkit.addPassFromUrl(url)→ presents Wallet add sheet.- iOS Wallet stores pass with NFC payload.
- Guest taps phone on NFC reader → door opens.
Google Wallet:
- Similar:
notification-servicegenerates Google Pay Passes JWT. - App calls
google-pay-passesAPI to save pass to Wallet. - Guest taps Android phone on NFC reader.
Security note: Apple/Google Wallet passes are NFC-based. The credential payload is signed by the lock vendor; Ghasi platform does not control the NFC payload format.
5. Key sharing (R3+)
- Guest can share access with a companion by sending an invite (email/phone).
- Companion receives a link → downloads the app → accepts invite → gets their own credential (derived, time-scoped).
- Managed by
lock-integration-serviceKeyShareaggregate.
6. Credential lifecycle
| Event | Action |
|---|---|
| Booking confirmed | lock-integration-service pre-generates credential; stored securely |
| Early check-in approved | Credential valid-from updated |
| Checkout | Credential revoked (lock-integration-service.revoke) |
| Room move | Old credential revoked; new credential issued |
| App uninstall + reinstall | Re-fetch credential from BFF on first open |
| Device lost | Guest can invalidate all credentials from Guest Portal /manage |
7. Offline behavior
| Scenario | QR/PIN | BLE | Wallet |
|---|---|---|---|
| App offline | ✅ QR/PIN shown from secure store | ✅ (credential embedded in BLE SDK) | ✅ (passes stored in Wallet, no network) |
| Lock server offline | ✅ JWT validated at lock, no call-home needed | ✅ Same | ✅ Same |
| Credential expired offline | ❌ Cannot renew — must go online | ❌ | ❌ |
8. Security requirements
- Credential payload encrypted at rest in
expo-secure-store(hardware-backed keystore where available). - Lock JWT signed with ECDSA P-256 (minimum). RS256 supported for legacy lock vendors.
- No biometric gate required for QR display (it's just scanning), but BLE unlock optionally requires biometric confirmation (configurable per tenant).
- Credential never logged to telemetry (only lock event metadata: timestamp, property, room, outcome).
9. Open Questions
- QR code refresh interval: QR JWT
expset to 24 hours by default. Should it refresh on each app open (longer-lived) or short-lived (more secure but requires network)? - BLE scan range: TTLock BLE range is ~10m. Should we prevent false triggers in corridors (proximity guard via RSSI threshold)?
- Staff mobile key: housekeeping staff need master keys for full-floor access. Is this covered by the same BLE credential model or a separate
MasterKeycredential type?