What are the advantages of using guardian_db?

Well, it was already well debated about why guardian_db or any token should or should not be persisted in the database. The main question is whether you will want to either track simultaneous sessions or revoke tokens. Most authentication systems with internet facing clients would want that IMHO.

There is another reason not mentioned here though: if you are using salts for your tokens.

As for whether to use Phoenix.Token or JWTs I will give some of my points here just to add more to the discussion (this should probably be moved to the bigger Phoenix.Token vs JWTs thread. If it’s not an issue I’ll post there as well).

Phoenix.Token is a simpler JWT that is not JSON at all :slight_smile:. What I mean is that it follows the “intention” of signing data and keeping its integrity. The difference is on the flexibility of each:

  • JWTs can do more than just verify the signature and expiration. Of course you could do the same in Phoenix but that would be up to the user. Things like validating issuer, “not before” and other default claims. You can normally add custom claims too.
  • JWTs allow for different signing algorithms. Phoenix signing is very similar to the HS*** family of algorithms for JWTs. They use a “password” and a digest algorithm (defaults to sha256 in Phoenix just like HS*** algorithms). The other algorithms use asymmetric cryptography (like RSA or elliptic curve cryptography).
  • Finally, and the reason for posting this here, is: one could argue about JWTs not providing salt option. Well, salts should be unique for each token if they are meant to increase entropy. If you are using a secure random then that is another reason why you should persist your token with its salt. I would even say that if you are using the same salt for all your tokens, then you are more likely to give an attacker information about your system than when using it without salts. Since the Phoenix.Token documentation doesn’t say anything about not using the same salt, then I guess this may be the common case.
2 Likes

In the context of Guardian, the salt is the secret_key, is not it? It does not change, it is set and fixed inside config files. If this is true, would be good idea to inject inside the encoded data some dummy random long string (different for each issued JWT)? Would that mitigate the effects of using the same secret_key for all tokens? Thank you.

It’s not JWT at all, JWT is a spec, it does not follow the spec in any format, json or etf or anything. It is very much a signed-or-encrypted data blob, which is also why it is much more lightweight.

Phoenix.Token is already built-in with signature and expiration, that is not up to the user, it already exist.

I’m
 not sure what you are saying here, what are you talking about? o.O

Phoenix’s default one is like that (which is perfectly fine for web use, if not even excessive), but you can replace it with any that you wish using any library of style you can think of, such as it is not limited to just joken or so.

Well Phoenix’s salt is called a secret_key key, Guardian’s salt is called a secret_key, so it follows. :slight_smile:

Overall, in my opinion, a token should be very short lived, like even it’s timeout should be measured in seconds. If you want to persist a session with the client then you should use Cookie’s. If you want to persist connection with a remote server then use a unique database entry that can be easily revoked. If someone starts talking about needing to revoke a token then I immediately think they are using the wrong thing for the wrong purpose.

Not really because even that new random data will be encoded with the same salt.

1 Like

Guardian.DB is an extension to vanilla Guardian that tracks tokens in your application’s database to prevent playback. With Guardian.DB, records of all generated tokens are kept in your application’s database. During each request, the Guardian.Plug.VerifyHeader and Guardian.Plug.VerifySession plugs check the database to make sure the token is there. If it is not, the server returns a 401 Unauthorized response to the client. Furthermore, Guardian.revoke! behavior becomes enhanced, as it actually removes the token from the database. This means that if the user logs out, or you revoke their token (e.g. after noticing suspicious activity on the account), they will need to re-authenticate.

Sorry if my writing was confusing. I’ll try to be more specific here. Let me just say that I am by no means a security expert or a cryptographer


You’re right. I did not mean to imply that Phoenix.Token is an implementation of JWT. I just tried to say that having structured data with an anti-tamper mechanism encoded in some hash is part of the implementation of both tokens. Though you are right that they differ in details and Phoenix.Token is way lighter than JWT (in terms of parsing structured data and validating).

Exactly what I’ve written before. What Phoenix.Token validates per token is signature and expiration. JWT has the concept of claims that can also be validated: nbf (token cannot be used before some moment in time), iss (who created the token) etc. We could add these info in Phoenix.Token and then validate those in user code. JWT takes these claims as part of their configuration so calling something like: MyJwtLibrary.verify(...) would already validate those. That was the intention here.

Claims are the way JWTs struct their data. As already mentioned, exp, nbf, iss, etc are standard claims (data in a token). Normally, JWT libraries allow you to add custom claims in your configuration or dynamically (per user or any rule you’d want). So, the approach is different than Phoenix.Token and may be more or less convenient to users of those libraries.

Agreed. I haven’t customised Phoenix.Token signing algorithms before and haven’t looked too much about it in Plug Crypto modules. From a very brief read through the docs we can customise the digest algorithm but not the encryption/signing. That is always a Password based key derivation function and could not accept RSA keys for example. But I may be wrong here as I truly haven’t dug deeper in the code.

A salt and a secret key are very different things for cryptography. The first one has the intention of adding entropy to the data being encrypted or signed and the later one is used in the cipher algorithm itself. The difference is like this: say you have a secret_key of 20 random characters and you want to encrypt/sign a string with 10 characters. Adding a salt of, say, 5 characters does not make your secret_key 25 characters wide but makes your string to be encrypted 15 characters wide. This makes a difference: if you are trying to decrypt a random hash generated without salt, you could use some dictionary of most probable combination of characters to see if the hashes match. When you salt the input it makes this kind of attack more difficult and most of the times impractical.

The issue is that when you salt all input using the same salt and if the input can be manipulated on the front end, then it is likely that you are giving hints as to how you are encrypting/signing your data giving an attacker more room to try other kinds of attacks.

Using the same secret_key for all encrypting/signing is ok because that is not an info that an attacker should have ways to tamper with. Usually, when you try to be “smarter” and have several secret_keys you might open up your security when trying to persist these different keys, coming up with a safe way of choosing which one to encrypt, having different timings and etc, etc, etc. So, I wouldn’t recommend that if it is not, at least, passed through some pen-testing.

Again, I’m by no means a security expert or a cryptographer so please correct me if I said anything wrong.

It is overheads like those, that most people would never use, that make JWT so much heavier and slower though


I know what claims are, what I did not understand is what you were asking, but you weren’t asking anything, rather describing claiming, just an issue in my perception of the text. ^.^;

True, though when most people salt things they just add some data to the stored data (I have a UUID generated in binary and attached to mine every time something is encrypted for example, I happen to have it double as the unique session ID). For higher end hashing (passwords and so forth) I use bcrypt, but then again I don’t need the data there, only confirm it.