🛡️ Enforcing Single-Session Login in a Flutter App: Auto Session Kill on App Close
FlutterPulseThis article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

Scenario: In many applications — especially in financial or enterprise sectors — users are restricted from logging in on multiple devices…
Scenario: In many applications — especially in financial or enterprise sectors — users are restricted from logging in on multiple devices at the same time. This requires robust session management with a crucial need: automatically delete a session when the app is closed or killed.
In this article, we'll walk through:
- Why this problem exists
- Challenges with app lifecycle in mobile and web
- How to implement session cleanup on app termination
- Using platform-specific approaches for Android and Flutter Web
🚨 The Problem: Concurrent Sessions
Let's say you're building an app where each agent can only be logged in on one device. If a user logs in on another device while still active on the first, the second session fails — unless we clean up the first session.
But here's the challenge:
Most users don't log out manually. They just swipe the app away or close the tab.
If you don't handle this gracefully, users will be locked out by a ghost session. 😬
🧩 The Challenge: Detecting App Termination
Unfortunately, app termination is tricky to detect reliably:
🟢 On Android
- If a user swipes the app away or removes it from recent tasks,
onTaskRemoved()in a Foreground Service is your friend.
🟠 On Flutter Web
- You can hook into
window.onBeforeUnloadto trigger last-second cleanup.
🔴 On iOS (not covered here)
- More restrictive and unreliable for background tasks.
✅ Our Goal
We want to delete the user session on app close (whether it's mobile or web) by calling an API like:
https://api/WebApiRequest/PostRequestinfo/{value}
{
"apiName": "Delete_Session",
...
}🔧 Implementation: Android Foreground Service
To handle Android app termination, we'll use a Foreground Service:
class SessionKillService : Service() {
private var userId: String? = null
private var sessionId: String? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
startForeground(1, createNotification())
merchantId = intent?.getStringExtra("merchantId")
sessionId = intent?.getStringExtra("sessionId")
return START_STICKY
}
override fun onTaskRemoved(rootIntent: Intent?) {
sendDeleteSessionRequest(merchantId, sessionId)
stopSelf()
super.onTaskRemoved(rootIntent)
}
}This service is started from Flutter using a MethodChannel, triggered when login is successful.
Flutter Dart Side:
void triggerSessionKillService({String? merchantId, String? sessionId}) {
const platform = MethodChannel('app.lifecycle.channel');
platform.invokeMethod('triggerService', {
"merchantId": merchantId ?? "",
"sessionId": sessionId ?? "",
});
}Now if the app is swiped away, the session delete request is fired via the native service.
🕸️ Implementation: Flutter Web Using sendBeacon
For web, the sendBeacon API allows us to send non-blocking data even as the browser tab is closing:
html.window.onBeforeUnload.listen((event) {
final data = { ... }; // JSON payload
final blob = html.Blob([jsonEncode(data)], 'application/json');
html.window.navigator.sendBeacon(webhookUrl, blob);
});This is perfect for short, critical requests that must be sent before unload.
⚠️ Avoid async/await or standard
http.post()insideonBeforeUnload— the browser may terminate it.
🔍 Debugging with Webhook.site
To test this behavior, use https://webhook.site:
- It gives you a temporary endpoint to receive HTTP POST requests
- You can inspect headers, payload, and status in real time
Just paste the generated URL in your sendBeacon code and trigger a page close. Magic! ✨
🧠 Wrap-Up
This pattern helps you maintain strict session control in Flutter apps by:
- Running a native background service on Android to detect task removal
- Leveraging the browser's
onBeforeUnloadfor Flutter Web - Ensuring that no orphan sessions are left open
🔒 It's a simple but effective way to enforce single-session login and avoid frustrating login issues due to stale sessions.
💡 Pro Tips
- For iOS: Consider using server-side session expiry policies, as background execution is limited.
- For Flutter desktop apps: Lifecycle management APIs are platform-dependent and evolving.
- Always fallback gracefully — like allowing a "force login" option to invalidate prior sessions.