Skip to content
This repository has been archived by the owner on Apr 28, 2020. It is now read-only.

Login beacon #52

Open
jace opened this issue Aug 16, 2013 · 14 comments
Open

Login beacon #52

jace opened this issue Aug 16, 2013 · 14 comments

Comments

@jace
Copy link
Member

jace commented Aug 16, 2013

Sites are often out of sync with Lastuser w.r.t the user's logged in state. The user may be logged into the site but not the app or vice versa.

The login beacon is a JS script loaded from the Lastuser server in all app sites that attempts to fix this:

  1. If the user is logged into Lastuser but not the app site, and the app is a trusted site OR the user has an existing access token to this site, it logs the user in automatically and prompts for the page to be reloaded. (Question: how does it login without user interaction? If an iframe, there's cross-site scripting concerns.)
  2. If the user is logged into the app but not Lastuser, it logs the user out immediately.

Questions:

  1. Should this script be reloaded for every page, using its own request as indicator of user state?
  2. Should the script be cached, and instead hit a beacon API endpoint that returns a lightweight result?
  3. What are the implications to server load on Lastuser if every page on every app loads it?
@jace
Copy link
Member Author

jace commented Aug 16, 2013

Login is defined by the contents of a signed HTTP-only cookie, so this script can only be loaded from auth.hasgeek.com (or whatever the app's login server is).

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Implementation:

  1. Script served from /api/1/login/beacon.js with a cache timeout of 5/10 minutes and mandatory parameters: key= client key, '&userid=local user id if present, blank otherwise,&login=local login endpoint,&logout=` local logout endpoint.
  2. JSON served from /api/1/login/status.json (no JSONP) with explicit no-cache, called by beacon.js to verify user status if it believes the user is logged in, but the client page indicates not, or vice versa. This is to get around the effect of a cache.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Scenario 1: User is not logged into either Lastuser or client app

  1. Client app requests beacon.js?userid=
  2. Script recognises server and client userid are blank, does nothing.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Scenario 2: User is logged into both Lastuser and client app, script is not cached

  1. Client app requests beacon.js?userid=x
  2. Script recognises server and client id match, does nothing.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Scenario 3: User is logged into Lastuser but not client app, script is not cached

  1. Client app requests beacon.js?userid=
  2. Script notices a mismatch, requests for status.json
  3. Script confirms user is logged in on server, proceeds to login on client.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Scenario 4: User is not logged into Lastuser but logged into client app, script is not cached

  1. Client requests beacon.js?userid=x
  2. Script notices mismatch, requests for status.json
  3. Script confirms user is not logged into server, logs out on client.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Scenario 4: User is logged into Lastuser but not client app, script is cached logged out

  1. Client requests beacon.js?userid=, gets cached copy
  2. Script believes server and client userid are blank, does nothing.
  3. FAIL

Possible fix: the logged out version is always served with no-cache headers.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Scenario 5: User is logged out on Lastuser but logged in on client, script is cached logged in

  1. Client requests beacon.js?userid=, gets cached copy
  2. Script believes server and client are logged in, does nothing.
  3. FAIL

Possible fix: don't cache logged in version either. What's the point of the separate status.json then?

@jace
Copy link
Member Author

jace commented Apr 9, 2014

The only sensible fix to the cache problems appears to be to (a) use database-backed sessions (#89) and (b) push notifications to client apps when a user logs in/out.

@jace
Copy link
Member Author

jace commented Apr 9, 2014

Push notifications can be used to force logout a user, but not for login, since we have a ready identifier (the cookie) for logout, but nothing for login. Therefore a possible solution is that the logged out beacon script is served with no-cache, while the logged in version is cached.

However, logged out pageviews far exceed logged in pageviews, so this makes performance slightly worse for the more common use scenario.

@jace
Copy link
Member Author

jace commented Apr 10, 2014

#89 has resolved the logout problem. When the user now logs out of Lastuser, they also logout of (most) client apps -- anything running the new Flask-Lastuser with login sessions.

The login beacon's job is now to facilitate login alone.

@jace
Copy link
Member Author

jace commented Apr 10, 2014

Looking at this afresh:

  1. The login beacon could be a static, cacheable resource that examines host cookies to determine course of action.
  2. The session cookie remains HttpOnly as at present since it's contents need to be private.
  3. Lastuser could set another non-HttpOnly cookie that simply carries a flag indicating whether a user is logged in or not
  4. The login beacon looks for this cookie and if it detects a user, it calls home to ask if it should initiate a login sequence. This part needs more clarification since multiple considerations apply.

@jace
Copy link
Member Author

jace commented Aug 25, 2014

The only way to read Lastuser's cookies from a client app website appears to be by using an iframe and reading that iframe's document.cookie, so that requires another endpoint that is loaded into an iframe:

  1. Iff there is no user session locally, the client app adds an invisible iframe (via baseframe's networkbar) that loads the beacon page from lastuser's API. Parameters include the client id and local login endpoint
  2. The iframe receives a JS-readable cookie that indicates if a user is logged in. It also contains a script tag whose code is custom-generated for the client id (and client id alone).
  3. If the client is trusted (hardcoded into generated script) and document.cookie suggests a user is logged in on Lastuser, it redirects the top frame to the local login endpoint.
  4. If the client is not trusted but a user is logged in, it phones home to confirm that the user has an access token for this website and that it's safe to log them in.
  5. If the client is trusted and a user is logged in but doesn't have an access token for this website, it can prompt the user to login.

@jace
Copy link
Member Author

jace commented Jun 8, 2018

Scenario 4 is still broken. Corresponding ticket in hasgeek/flask-lastuser#31

@jace jace reopened this Jun 8, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant