1

I am trying to maintain user login session(1 hr) in my Android application. When user logs in, I am receiving login time(StartTime) and session end time(Timemout) from server.

I am comparing received login time + session end time with my current device time using System api (System.currentTimeMillis()).

My problem is that user can manipulate this System.currentTimeMillis() by changing location or by changing clock time in their device and can have infinite login session.

I also tried using SystemClock.elapsedRealtime() which is dependable on boot time. Where user can reset or manipulate the time by rebooting the device.

Is there anyway to maintain 1 hr login session?

StartTime and Timeout time receiving from server.

((startTime + timeout) > (System.currentTimeMillis()/1000))

or

((startTime + timeout) > (SystemClock.elapsedRealtime()/1000))

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • Changing location will not affect `System.currentTimeMillis()`. Changing clock time will, of course. – Ole V.V. Aug 06 '19 at 16:45
  • Possible duplicate of [How to use an Internet time server to get the time?](https://stackoverflow.com/questions/4442192/how-to-use-an-internet-time-server-to-get-the-time) – Ole V.V. Aug 06 '19 at 16:47
  • 3
    You could make the server be responsible for keeping track of the login times of users? – Logan Aug 06 '19 at 16:47
  • 3
    This is something the server should be responsible for. The client should only use it as an optimization, to provide a better user experience for the happy case. The server should reject requests if the user has timed out. – Gabe Sechan Aug 06 '19 at 17:39
  • @CartOfSwine If I make the server responsible for this, it will increase the numbers of API call to just check the Session time, right? – CrazyProgrammerThing Aug 06 '19 at 17:43
  • @GabeSechan I wanna make user login again when session ends before making any API call. Anyway I liked your suggestion – CrazyProgrammerThing Aug 06 '19 at 17:46
  • 2
    @CrazyProgrammerThing You can make the API return an unauthenticated response, and when the app receives that it pops up a login screen. When they login they then get redirected to the original page and retry the request. – Gabe Sechan Aug 06 '19 at 17:48
  • @CrazyProgrammerThing Here is what I would do. When doing authentication, have the server respond with the amount of time the login has left. Start a timer for however long the server returned app side, and invalidate once it completes. That way you don't have to ping the server a lot. You are only checking up on app launch when you set up your timer. – Logan Aug 06 '19 at 18:09
  • So if the app is running, either it is unauthenticated and waiting for the user to login, or it has a timer running at the end of which it will revert to the earlier state. You will want to use a Timer implementation that is not sensitive to the system time as detailed in this answer https://stackoverflow.com/a/18803742/8359895 – Logan Aug 06 '19 at 18:20
  • @CartOfSwine currently I am using time-based or counter-based system. I found out that user can manipulate device time or kernel based counter, so I can not relay on counter or device clock time. If you are saying system.nanoTime() can not be manipulated I will definitely use this method. – CrazyProgrammerThing Aug 06 '19 at 18:44
  • 1
    @CrazyProgrammerThing Yes you could use nanoTime in this instance. You could also use something that is based on it, such as a ScheduledThreadPoolExecutor, so you don't have to reinvent the wheel. – Logan Aug 06 '19 at 21:11

2 Answers2

2

The goal here is to make sure your sessions do not exceed a certain length of time regardless of any date/time changes on your device's local time. The one constant here is your server's time so let's leverage that.

  1. On app launch, make your app query the server to see if it has an active session. If not, present the user with a login screen.
  2. If there is an active session, the server should return the remaining duration of that session. This means that your server will keep track of which devices logged in and when the did so. That way, when an authentication request comes in, it checks its listing for successful logins in the last hour and returns the difference between the current time and the last login time. If there are no successful logins in the last hour it fails the request
  3. App side, when an authentication request succeeds we start a timer for the length of time returned from the server. You can implement this yourself, or you can just use a ScheduledThreadPoolExecutor. Regardless, your timer cannot use System.currentTimeMillis() in it's implementation or it will be affected by changes to the local time. Refer to this answer for more info on that.
  4. When the timer finishes, you can then lock the user out and force them to login again, or simply let them stick around until the app is shut down. That is up to you and your priorities regarding user experience and security.

In short, the app exists in one of two states at all times. Either it is unauthenticated and waiting for the user to login, or it is authenticated and on a timer to when it will lock the user out again. This way, you don't have to ping your servers quite so often to check session status

As mentioned in the earlier link, System.nanoTime() is a good tool to use in a timer that should not be affected by changes in the local time. More details in the java docs

Logan
  • 92
  • 8
0

This can be handled at server side. You may create a session on the server for the user which will be timed out after 1 hour (specified in requirement).

In this case you can notify user about session logged out in any of these ways:

  1. If any requests comes after session timed out then it will notify user as session logged out.

  2. The moment session gets expired, server can send notification to client as session logged out.

Logan
  • 92
  • 8