Multi-Device Login Implementation in Mobile App
Multi-device login — user ability to be logged in on multiple devices simultaneously. iPhone, iPad, work Android — all show up-to-date data. Technically, this is about proper token management and state synchronization between devices.
Token Architecture
Each device gets own pair access_token + refresh_token. Backend stores sessions table:
CREATE TABLE user_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
device_id VARCHAR(255) NOT NULL, -- unique device identifier
device_name VARCHAR(255), -- "iPhone 15 Pro", "Samsung Galaxy S24"
device_type VARCHAR(50), -- ios, android, web
refresh_token_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT now(),
last_active_at TIMESTAMPTZ DEFAULT now(),
expires_at TIMESTAMPTZ NOT NULL,
UNIQUE(user_id, device_id)
);
device_id on Android — Settings.Secure.ANDROID_ID (doesn't change on reinstall, resets on factory reset). On iOS — identifierForVendor (resets when all developer apps deleted). For more stable iOS ID, generate UUID on first launch and store in Keychain.
device_name from: Android — Build.MANUFACTURER + " " + Build.MODEL, iOS — UIDevice.current.name.
Device Limit
Some apps limit active sessions (streaming services, financial apps). On limit exceeded, backend returns MAX_DEVICES_REACHED with active sessions list — mobile offers user to choose which session to close.
sealed class LoginResult {
data class Success(val tokens: AuthTokens) : LoginResult()
data class MaxDevicesReached(val activeSessions: List<DeviceSession>) : LoginResult()
data class Error(val message: String) : LoginResult()
}
@Composable
fun MaxDevicesScreen(sessions: List<DeviceSession>, onRevoke: (String) -> Unit) {
Text("Device limit reached. Log out from one:")
sessions.forEach { session ->
DeviceSessionCard(
deviceName = session.deviceName,
lastActive = session.lastActiveAt,
onRevoke = { onRevoke(session.id) }
)
}
}
Data Sync Between Devices
When user changes data on one device — others must know. Mechanisms:
Push notifications with data payload — on profile change on device A, backend sends silent push to all user's other devices. Device B wakes, syncs in background.
WebSocket — if app uses real-time, sync events go through same channel.
Pull on foreground — on exit from background (onResume / applicationWillEnterForeground) request fresh data. Cheap to implement, suits infrequent changes.
For financial apps — balance and transaction history sync on every background exit mandatory. Cached balance on other device must be marked stale after certain time.
Multi-device login implementation (multiple tokens, sessions table, device list) — 2–3 weeks. With data sync between devices — 3–5 weeks. Cost estimated individually.







