How do you do tokens and permissions? #REST

In a REST API, how do you handle tokens and permissions?

On tokens, once you have retrieved the token from the Authorization header, how do you verify you have issued that token in the past? Do you store it in your database and check whether an entry for it exists (and thus make sure you have indeed issued it) and what user it is liked to? Do you have a separate table for tokens just so you can have numerous tokens for an user, over a single one that is perhaps stored in the users table in a token column? Do you use Phoenix.Token and verify/4 it to get its stored user id and go from there? Why would you use Phoenix over generating a random string of a certain length each time you want to issue a token - how would this be done in Elixir?

On permissions, lets say we have a specific resource post that you want an user to have access to edit but not delete. How do you store and handle this kind of permissions? Perhaps a table named post_permissions with a bit with the user’s permissions? That would fit the case where there’s a single resource to handle, how would it go though for a system where post is just one of the many restricted resources?

3 Likes

Just use Guardian: https://github.com/ueberauth/guardian

I am using Guardian to do everything you discuss in your post.

The library guardian handles most of these things. The token does not have to be stored in a database, instead it is encrypted using a secret key. If someone provides a valid token (ie: it was encrypted with the correct key) then you know it was issued legitimately without checking a database. Unfortunately you usually do need to store some state in the database to handle sign out (or a token being invalidated for other reasons). In the case of Guardian they recommend storing the token in a database so that it can be removed when you revoke it (GuardianDb exists to make this easier.

how do you verify you have issued that token in the past?

You just attempt to decrypt it. If you use JWT there is a standard method for this.

Do you store it in your database and check whether an entry for it exists (and thus make sure you have indeed issued it) and what user it is liked to?

That’s one way to do it. Another way is to encode a date that the token was issued and then just store in the database the date the user last logged out. Any token with a date older than that will be rejected. This means that a logout would kill all tokens for that user (which may be a bug or a feature).

Why would you use Phoenix over generating a random string of a certain length each time you want to issue a token - how would this be done in Elixir?

If you are going to store each token in the database with some metadata anyways then that would probably work fine if it is a sufficiently long cryptographically random string. Honestly I like that technique but if you use a JWT (or similar) then you have the potential for stateless logins. You could have ten load balanced servers and as long as they all have the same secret key they can individually validate tokens and derive the user and their claims without hitting a database or requiring any single point of failure.

How do you store and handle this kind of permissions?

If you use JWT you could use claims for this. From my experience a lot of people end up just rolling their own permissions table that links to users or something similar.

1 Like

Specifically: http://blog.overstuffedgorilla.com/simple-guardian-api-authentication/

1 Like

I agree that the link wfgilman posted solves all of the problems except it is important to keep in mind that the logout technique using the default revoke! is not 100% secure. From the guardian readme:

By default, JWTs are not tracked. This means that after ‘logout’ the token can still be used if it is stored outside the system. This is because Guardian does not track tokens and only interprets them live. When using Guardian in this way, be sure you consider the expiry time as this is one of the few options you have to make your tokens invalid.

That means that if you issue a token that is valid for 10 days and then a user’s cookie gets stolen, they cannot just click logout or change their password or anything in order to secure their account. The token will continue to work for the full 10 days.

Good point. I use GuardianDB to store the tokens and a sweeper to delete all expired tokens. In your api pipeline in the router you can ensure that a resource can be loaded from the token provided (i.e. checked against the database) and invalidate the request if not.

1 Like

Thanks for the replies. :slight_smile: In a previous topic, I was told not to use Guardian over Phoenix.Token when not encoding permissions into the token itself. Which gets me to a few questions; do you agree? In the case I am storing the tokens manually and only need to verify and sign it (with a secret key), wouldn’t Phoenix’ approach just do fine? And in the case I am anyway checking against a database whether a token is still valid, why would I need to encode an user id into the token whilst I can just get what user it’s linked to from the previous validating step? Thus, wouldn’t generating a random string securely do the trick instead?

On both cases, signing and generating a random string, why Phoenix.Token and not Joken or any other library? How would you generate a random token, perhaps doing this or using a more dedicated library?

What are the pros and cons from a security perspective? In what way is a signed token safer compared to a random string?

Two standard ways when in-system like that. Either put the permissions in the database and look up the user’s permissions when needed, or store the permissions inside the Phoenix.Token directly, saving the database call, however that also means it will not be cleared out if, say, they are removed permission from later, however using very short-lived tokens is perfectly fine for that.

@satom99 is already using Phoenix.Token, which can do everything Guardian can do in this context but without the extra dependency and cost of JSON deserialization

People really need to quit recommending Guardian for areas where it is ill-suited. This is a perfect user-case for what they are already using, Phoenix.Token. Guardian is great for things like passing credentials to a remote non-connected server. If you are using it in the same server then it is just needless overhead.

And doing that you then remove the entire advantage of using Guardian at all (which is to keep you from having to hit a database when doing a cross-site call), why use Guardian at all in this case??

Still hitting the database, you may as well put the permissions in the database itself then and don’t use a token at all but instead just the session to hold the link, of which you can easily wipe if, say, they log out elsewhere so the session is then wiped from the database preventing replay attacks. Guardian on the other hand would let you trivially perform replay attacks, so quit suggesting it please! ^.^;

Stateless logins are nice, but you generally want short-lived tokens then to minimize replay attack abilities, and JWT is useful only if passing to another server; again if you are doing this all in the same server that you control then use Phoenix.Token, it is not as heavy, can hold arbitrary data, is faster, but does require that the server is on the BEAM or so all using the same key, JWT allows you to send data safely from server-to-server.

JWT claims are just simple on/off, fine for very simple things, but not good for more detailed permission types.

Exactly! This is the replay attack, they just replay the old token. If it is all in-system then better to keep it in the database and don’t use tokens at all!

If you are having Guardian hit the database anyway, they why are you using Guardian at all?! It makes no sense!

  • If you are doing the authentication and authorization all in the same server and you’ll be hitting the database anyway, don’t use tokens, just use Phoenix’s Session and the database, you have significantly greater control.
  • If you are doing the authentication and authorization all in the same server and you don’t always need to hit the database for short-lived authorization permissions, use Phoenix.Token and put the allowed permission inside the token itself (like via Phoenix.Token.sign("perms", [:read, :edit]) or whatever, you can encode whatever you want in it in any form that you want).
  • If you are doing authentication on one server and doing authorization on ‘another’ server and those two servers do not use the same secure phoenix keys, then and only then is JWT (Guardian) useful. Don’t use it otherwise, it is not safe and/or not secure in other contexts.
6 Likes

I probably didn’t make it clear enough, but I was not suggesting or recommending anything. I was trying to offer up information on how one tool addresses the problem (and in fact it seems like it is the most popular and/or well known tool) for the sake of discussion… and it seems to have worked because your post has a lot of great information :stuck_out_tongue:

My question as well, that’s why I thought it was important to point it out. If your logins are no longer stateless (and they probably should not be in this case or even in most cases) then I have no idea why you would want Guardian.

What I was trying to do is explain that systems like Guardian try to simplify authentication by making it stateless, etc but then the simplicity all gets rolled back to re-introduce necessary features (like logout) but you’re still left with the security and efficiency concessions that were made in order to achieve the simplicity that you don’t get anyways.

Furthermore, it’s also worth mentioning that there is a school of thought that JWT itself is completely unsuited for this type of work and that it is only meant for short lived, single use tokens (like you said). If that’s true then it actually sounds like Guardian is fundamentally flawed and almost nobody should use it since their own examples seem to use stateless JWT for persistent single server logins.

Thank you for adding so much to the conversation, OvermindDL1. I learned a lot from your post! I think you made it clear that stateless authentication isn’t really something to strive for in a case like this and that Guardian is not the right tool. Very curious if there are any guardian fans who disagree.

Does this end up being similar to the random string approach except you are letting Phoenix (which just uses Plug) generate a session ID which essentially becomes the random string? I can see that this is a quick and easy way to achieve that because it takes care or storage as well, but I think the default storage system does not persist when you restart your server so everyone would get logged out on restart unless you implement some sort of database-backed session persistence.

And make sure that if you do this you do not also include some sensitive information. It is signed but not encrypted.

This sounds right and I didn’t realize it until reading your post. They should just say that up front in their readme :slight_smile:

Not so much a random string as it is an encoded cryptographically random binary, so it is better than what most people would ever do. ^.^;

Actually one of its default stores (I think ‘the’ default maybe? Don’t recall) is storing it in an encrypted Cookie, which will persist. I just store a session ID on it, which is generated by my database and can be revoked in an instant at any time. ^.^

Yeah I wish they would… :frowning:

@OvermindDL1 I really appreciate your thoughts here, I learned a lot.

We’re using long-lived tokens which just serializes some basic information, like user ID. We’re checking the token against the database on each request to ensure it’s valid. Guardian works great for this use case because it has a lot of conveniences for verifying the token in the header request and tracking tokens in the database. I would have to roll my own if I was using Phoenix Token. It’s not stateless, but for long-lived tokens, it doesn’t sound like there is a stateless authentication solution for an API.

Actually there are a variety of helpers that add plugs like Guardian’s for ease of use with phoenix tokens, this is near the top of my search:

As well as they are so easy to write manually that there’s almost no point to add a dependency. ^.^;

1 Like

Just curious, but why discourage using Guardian? Do you think it’s overkill?

1 Like

Other than it is the wrong abstraction? A couple of other reasons:

  • Significantly larger in payload because of all the packed json stuff required by the JWT spec.
  • More costly to (de)serialize, which just makes your request take that ever slightly bit longer.
  • Yet Another dependency when it adds about nothing unless JWT is really needed.
  • To use it properly you either need to push it in the DB yourself anyway or bring in Yet Another dependency like guardian_db.

Etc… ^.^;

4 Likes

Thanks, I appreciate your thoughtful comments as always.

2 Likes

Thanks, I try. :slight_smile:

And another note:

It is not that it is overkill, Phoenix Tokens and JWT tokens can encode the same information, it is just that JWT is designed for arbitrary (as in to/from servers that you do not control) server-to-server communication and has a lot of overhead because of that so the format is ‘universal’.

Hello, since we are in the topic of tokens, I have a question. I hope it doesn’t skew too much from this thread’s topic.

In “Programming Phoenix” page 186 it says

For request/response–type applications, session-based authentication makes
sense. For channels, token authentication works better because the connection
is a long-duration connection. With token authentication, we assign a unique
token to each user. Tokens allow for a secure authentication mechanism that
doesn’t rely on any specific transport.

Programmers often ask why they can’t access their session cookies in a
channel. The answer is that this would be insecure over WebSockets because
of cross-domain attacks. Also, cookies would couple channel code to the
WebSocket transport, eliminating future transport layers. Fortunately, Phoenix
has a better way: the Phoenix.Token.

Here is my translation. Please tell me if I am wrong

For channels, token authentication works better because the connection
is a long-duration connection.

It would be silly to hit the db every few seconds just to retrieve the session

Also, cookies would couple channel code to the
WebSocket transport, eliminating future transport layers.

If you don’t want HTTP that’s fine. Use something else. Just send the token

Programmers often ask why they can’t access their session cookies in a
channel. The answer is that this would be insecure over WebSockets because
of cross-domain attacks.

Can someone explain this last point?