Solving offline logout problem

A few days ago I had an interesting brainstorm with Chris Le Roy regarding offline logout process — the scenario when the user tries to log out but he is not connected to the internet. At first glance, it seems simple, but there few interesting problems related to security.

The content of this article can be applied to both Android and iOs applications and even other clients that store session tokens.

Before we go there let’s consider login and online logout scenario to have a clear picture of how our client is dealing with authentication.

Nothing fancy here. After the application starts user enters email and password, press login button and application calls appropriate endpoint backed (server side) passing user credentials.

For security reasons, we don’t want to store user credentials on the device because this would allow a potential attacker to steal them in the future. That’s why our authentication request will only send credentials entered by the user and retrieve authentication token that we will store on the device (instead of entered user credentials).

From now on each request our app make to server will require this token. The backend will check if the token is still valid and return data or adequate error.

At backend this token is linked to a particular user account, so each time we send or retrieve data server will be operating in a context of that user e.g. calling getAccountDetails will return data for a specific user.

The token is also linked to particular device meaning if a user will login twice from two different devices each device will retrieve different token.

To make our communication more secure we should consider implementation of certificate pinning (trust only certificates signed by certain certificate, not certificate authority that can be compromised)

When application hits logout endpoint server will invalidate the token and optionally perform additional operations like unregistering device from Firebase (push notifications will not be delivered to this device).

From this point, any other request using this token will fail because session authentication token (linked to a certain device) is not valid anymore.

Now we are getting to the tricky part. What should happen when user press logout button when he is offline? How our application should behave under the hood? Should we even show logout button at all if there is no internet connection?

Let’s start with showing or hiding logout button. Different applications solve this issue in different ways. Facebook application does indeed show logout button, but Youtube developers decided not to do it. This behaviour is probably a result of very important difference between those two application:

  • Facebook explicitly asks user to login after installing and launching the application, so explicit logout (showing logout button) is natural and associated action at the end of the flow.
  • Youtube utilizes Google account credentials that every user already have before installing application on the device (this account is required to access Google Playstore), so user never explicitly login into Youtube application.

Let’s assume that our app is similar to Facebook — our user needs to explicitly login into our application. The easiest solution for offline log out would be to disable ability to logout when user is offline. However we want to improve security, so we want to allow ability to log out when app is offline. Let’s consider few options.

We could simply delete local authentication token after pressing logout button. Next time when user launches the app we verify that that token is not available on the device and we display login screen. Sounds good, but there are few problems with this solution. First problem is potential security risk (token at backend is still valid). Another problem are the notifications. Most of the applications utilise some kind of push notification API (PubNub, Firebase, etc.). Usually, backend registers the user device to receive push notifications. We need a way to unregister the device, so user will not receive any more the notifications. In our case, user would receive notifications even if he actually logged out, because backend wasn’t notified about the logout.

As a fix for this problem we might consider (Edit: ignoring notifications when token is not present on the device) or mark locally token as invalid, but do not actually delete it. This potentially fixes our problem, because when user launches the app we would again display login screen and additionally perform logout request to a server. At first glance this may seems as good solution, but there is a potential security risk here.

Let’s assume we are using medical application, banking application or some other application containing sensitive data. We perform offline logout and borrow our phone or our phone is stolen. The attacker can copy all the application data and retrieve token (which is still valid on backend) and this will allow him to hijack the associated session. Attacker to make a request using tool like Postman to retrieve sensitive user data.

There are few other scenarios worth considering:

- Our user does a backup of the app data using Titanium Backup (this backup app alone have 10–50M users) then logs out from the app — valid token still exists on the device.

- Our user was at the conference and used the public wifi network — attacker used Main in The middle attack to hijack his token. Latter user logged out from the app, but attacker still have perfectly valid token

There is important lesson here — user assumes that there is no way to access account from this device because logout was performed properly, but the device still stores valid token that allows accessing user personal, sensitive data.

Before we try to fix it, let’s recap our goals. We want to:

  • remove token from the device in order to minimize possibility of launching attacks over hijacked sessions (minimize security risk)
  • have ability to properly logout the user when the device is online in order to stop push notifications to be delivered to the device and invalidate session token at server-side.

We could create endpoint working without authentication token that will allow unregistering the device using some unique identifier e.g. user email. However, that’s is not ideal scenario because a malicious user could constantly disable accounts of other users forcing them to log in again (unlikely but possible scenario).

The solution for our problem is introduction of 2nd token — logout token. Each time our user logins he receives authentication token and logout token. Both tokens are stored on the device.

Logout token would be valid only for single usage and only for logout endpoint call.

Now when our user is offline and clicks logout we delete authentication token (disabling ability to retrieve sensitive data) and leave logout token so user can still log out properly. We should schedule a Job that will be executed later and that will try to perform logout using logout token.

This way we will be able to log out the user properly and diminish security risk.

Keep in mind that there may still be the cases where logout token will never be sent e.g. user loses or destroys his phone. That why token should be linked to some kind of expiration date (Absolute/Idle/Renewal Timeout) e.g. the token isn’t used for 4 hours then it is invalidated.

We should also consider implementing renewal token timeout just to keep our users safe in some scenarios like one-time token hijack from public wifi.

Offline logout is not difficult to handle, but as you can see it requires a little bit of effort to make it right and secure. I hope this article made this process much easier to understand in terms of tradeoffs and potential security risks.

Special thanks go to Chris Le Roy, an Android security expert.

👉 Follow me on twitter to stay tuned.

👉Android Developer Advocate at Vonage 👉Author of “Android Development with Kotlin” book 👉Follow me on twitter to learn more https://twitter.com/igorwojda