Hey, I’m implementing a user authentication using a users table in FaunaDB following the tutorial in the documentation. My application is a nextjs app that has an api that handles all the connections to FaunaDB. When a user logs in I save the secret in a secure, signed, httpOnly, sameSite cookie and return it to the user.
So, my questions:
Is it “safe” to save the secret in a cookie or is there some other preferred way?
For how long are the secrets valid, is there some ttl or are they forever?
I’m also setting up user roles, is it possible to get all the privileges for a specific user in json or something?
There are many ways, saving the secret in a secure, signed, httpOnly, sameSite cookie is probably the best you can do. If you are really paranoid about security the only extra thing you can do is to save a secure 100% random session ID instead and exchange that for a FaunaDB token in the backend. The only thing that buys you is that if someone somehow gets access to what is stored in httpOnly cookie (highly unlikely) then he can only go through your backend to get data and not via FaunaDB directly.
By returning it to the user you are actually cancelling many of the security benefits of httpOnly. As long as you only store it in memory doing this httpOnly cookie (for page refreshes I assume) + in memory approach is still much better than plain cookies or localstorage. What you can do better though is have that token in the httpOnly cookie be a different token (a refresh token basically that can only create access tokens) and the one you send to the user would be a very short-lived access token (e.g. 10 mins). I just finished a repository explaining that and am writing as we speak. Not sure when it will go live though, probably in a few weeks.
You can specify a ttl both on using Login() as well as when you create a token manually. There is a disclaimer though, tokens with a ttl are reclaimed as a best-effort and that might take a while since it’s currently an async job. For short-lived tokens, that matters and we are currently in the process of changing that behaviour so that ttl is respected as exactly as possible.
From the top of my head I don’t think we have something like that.
Thank you for your thorough answer @databrecht. Regarding the cookies, what I meant by returning it to the user is setting it in a set-cookie header in the response. So I assume that’s the most safe way, except for having a random session ID in between as you mentioned?
Regarding the privileges, would it be possible to do this for a role, i.e., if I know that the user is an admin, can I get all the privileges set for that role in some way?
Another question they came to my mind, is there some dedicated method to easily check if a user’s secret is still valid. I saw some methods to check the credentials but I would just like to find out if the secret is good or not.
Yes, correct, sorry for my missunderstanding, I saw many code-bases that save tokens in httpOnly cookies and then send it to the frontend to be kept in memory so I assumed that was what you meant . ( These approaches do make sense, they essentially do that to avoid keeping the secret in plain cookies/localstorage since in memory is still much better than those but you will lose it upon refresh)
Yes! Roles are documents, just like everything in the database so you can Get() them For example, the following will get all your roles:
No at this point you simply get ‘unauthorized’ if you try to use it and do something.
You could however if you want something like that take the Session approach where you actually store documents yourself for a ‘session’. For example:
You can easily add a ‘valid_until’ or calculate on the fly whether the ts is still valid on such a document. In your roles you could fetch the session via Identity(), verify whether it is still valid and then get the actual account (since we keep a reference in the session) to continue your business logic.
Cheers! Isn’t the only difference between session cookies and persistent cookies that the session ones expire when the browser is closed? I mean, if I have them both as httpOnly I assume they are equally as safe if you just consider the cookie aspect.
I think you are confused by how I used the word session. I wasn’t talking about sessions in the context of cookies. I just meant that you can create a ‘document’ (and I call that session) in a specific collection where you will create your tokens upon. Since you can’t access tokens in your roles but you can access the document that is linked to the token you could write a role that checks whether this document is still valid (up to you how to determine valid, by checking the time it was created, or writing a is_valid_until on the document). In my case, I consider that document a ‘session’.
If you need a ‘is valid check’ in your application for tokens, that could be a workaround (there are cases where you want to take an action when someone connects with an invalid token, in such a case, this workaround is handy).
Don’t worry about it though, it might all sound a bit too confusing if you didn’t need that.
The short answer is that we do not have a dedicated method to check if a user’s secret is still valid.