Skip to main content

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:

MethodPhaseTenant requirementGuest requirement
QR code / PIN code (static, displayed in-app)R2Any lock with PIN/QR scannerNone (no BLE, no Wallet)
NFC tap (Android)R2NFC-capable lock; Android NFC reader appAndroid with NFC
BLE credential (TTLock BLE, Dormakaba)R3BLE-capable lock vendor SDKmobile-key-ble flag on; Bluetooth permission
Apple Wallet key passR3Apple-approved lock vendor (Assa Abloy, NXP)iPhone with iOS 16+
Google Wallet key passR3Google-approved vendorAndroid 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:

  1. Lock vendor (e.g., Assa Abloy Incedo) provides Apple Passkit PKpass.
  2. lock-integration-service generates PKpass and signs with Apple certificate.
  3. App receives PKpass download URL.
  4. expo-passkit.addPassFromUrl(url) → presents Wallet add sheet.
  5. iOS Wallet stores pass with NFC payload.
  6. Guest taps phone on NFC reader → door opens.

Google Wallet:

  1. Similar: notification-service generates Google Pay Passes JWT.
  2. App calls google-pay-passes API to save pass to Wallet.
  3. 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-service KeyShare aggregate.

6. Credential lifecycle

EventAction
Booking confirmedlock-integration-service pre-generates credential; stored securely
Early check-in approvedCredential valid-from updated
CheckoutCredential revoked (lock-integration-service.revoke)
Room moveOld credential revoked; new credential issued
App uninstall + reinstallRe-fetch credential from BFF on first open
Device lostGuest can invalidate all credentials from Guest Portal /manage

7. Offline behavior

ScenarioQR/PINBLEWallet
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 exp set 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 MasterKey credential type?

References