Authentication and Cookies - sanity-checking request


#1

So, I know this has been done a fair bit already, but I wanted to run this idea through the Ember community for another set of eyes.

I’m writing a fairly simple emberjs app which looks kind of like a specialised newsfeed. Events happen, my users need to know about them. There’s fun stuff that makes it Different, but that’s not important here. There’s an API endpoint run as a ruby/rails server which serves up stuff like /api/users/:user_id/feed/:feed_id sort of stuff.

I’m handling authentication using omniauth, and since I’m writing this app for an internal use and my foundation uses google apps (free for nonprofits, whee), I can just hardcode in “just use google oauth2” and be done with it - no need to store passwords or anything. Easy.

I do the standard thing and store authentication data in ruby’s session store, and as I understand it the cookie I hand back is actually just a session identifier and it’s all secure and stuff (provided I make a new secret key), and while it’s vulnerable to normal session problems (fixation, hijacking), this isn’t new or interesting. Same as always.

The problem I’m having is actually communicating which user the currently-active user actually is. If they want to view their feed or edit their profile, they need to go to the /api/users/N for their personal N. Any other number in that path returns a 401 from the server side (session checking). At first, I put an additional endpoint in my api, serving the current session user as /api/users/current, but all the major persistence frameworks had a real problem with that- they really want the object’s API path to contain the actual id (so I can’t serve {name: eric id:2 email:eric@awesome.com} as json response on /api/users/current and have the resultant model get the id field to be 2 - the ID on the model ends up as “current”, somewhat understandably, but also frustratingly.

Rather than wrestle with the persistence libraries, I decided to just hand the user_id value off to the client in a cookie. So now, my “are you logged in” checks (which live in AuthedRoute that all my authed routes extend) look for the existence of that cookie and set a current_user on their controller.

The problem that I’m worried about is it feels a tiny bit less secure passing user_id in the clear. It probably isn’t an issue - all my api endpoints have before_filters on them requiring logins, and I’m not worried about non-logged-in users seeing my empty templates (they’ll redirect to the please-log-in view if there’s no current_user), but it has been a loooong time since I’ve worried about actually implementing authentication in the client side (this project is my first real foray into webapp dev since ye olde cgi-bin on apache days in the late 1990s, no joke), so I wanted to run this idea by the community before I made some kind of Huge Mistake.


#2

pfooti, I’m interested in the same thing. I’m an ember novice and I don’t have the answers, but I’m evolving my own login scheme based on Mozilla Persona. I’ll put up a gist when it’s working as I want it to work.

Discourse is obviously doing login and my best guess (without looking at their code yet) is that they make an effort to keep the logged-in state synchronized between the client and server. At the minimum, the client will want to test whether a user is logged in or not and disable parts of the UI that are off limits without an active login.

I think that the obvious place to hang the login state in the client is on the App itself. Much of the UI may depend on it, so it will need to be accessible to most views in the application. I haven’t learned about mixins yet, but I’m hoping that will be the answer.

The server will be responsible to know who is logged in so that it can restrict access to resources by identity. Also, it can never trust anything the client sends to it; it must always use its own state (most likely session state) to determine the authenticated entity. But, with an ember app, most of the traffic between client and server will be to access and manipulate resources. It’s not like you can just ship back a 401 html page.

I have a suspicion that I’m making this more difficult than it should be. The ember screencasts on this topic only give the example of a server that is entirely responsible for validating the username and password. This seems different from the case where a third-party authentication service (OpenID, Persona) is involved and I haven’t worked out corner cases or other security issues (anti-csrf) yet. One step at a time.


#3

Thus far, it seems to be working okay. All my really-important data is all handled on the server side using traditional rails sessioning, but I do that cookie thing. That way, the user shouldn’t see a route that they don’t have access to, but if they do ask for it, I’ll return 401.

This has the benefit of being really tidy - in my “are you allowed to see this” code on the rails side, I check to see if the currently-logged-in user is an admin, and if so I’ll disregard the “is the currently-logged-in user the same as the data-owning user” results, allowing admins to look at regular user data when needed.