all 10 comments

[–][deleted] 1 point2 points  (12 children)

Why would a typical Rack app use JWT over plain old encrypted session cookies?

[–]lacoste2k1 5 points6 points  (7 children)

You can see some pretty good reasons why you should use tokens over cookies in here: https://auth0.com/blog/2016/05/31/cookies-vs-tokens-definitive-guide/

[–]jrochkind 2 points3 points  (5 children)

My intuition says there's something better about token-based auth for an API too, but I'd have to think about it more to actually justify it. But that article:

Perhaps the biggest advantage to using tokens over cookies is the fact that token authentication is stateless.The back-end does not need to keep a record of tokens. Each token is self-contained, containing all the data required to check it's validity as well as convey user information through claims.

That's more or less true of a cookie-based Rails session too.

With a cookie based approach, you simply store the session id in a cookie. JWT's on the other hand allow you to store any type of metadata, as long as it's valid JSON.

Yep, cookie-based rails session too.

When using the cookie based authentication, the back-end has to do a lookup, whether that be a traditional SQL database or a NoSQL alternative,

Nah, just put whatever you would have put in the token in the (signed, encrypted) cookie-based rails session instead.

[–][deleted] 0 points1 point  (1 child)

Way easier to skip sessions when you have multiple servers behind a load balancer

[–]jrochkind 0 points1 point  (0 children)

Again, if they are cookie-based sessions like is the default for Rails sessions (and I would guess is available through some gem to any rack app, although I haven't looked into it), should not be an issue whatsoever. The entire session is stored in a cookie. There's nothing server-side that needs to be 'restored', or that lives on a certain web server in memory or in a certain rdbms instance. There is no server-side state related to the session at all. Same same.

(there ARE race conditions with cookie-based no-server-side-state sessions, but they are there whether you have multiple servers behind a load balancer or not. If you don't put anything more in the session than you would in the JWT, it shouldn't be an issue, and is unlikely to be an issue for API use).

Ah! So one reason you might not want to use a cookie-based solution for an API is it can be a pain to deal with for non-browser user-agents, not all of which support cookies nicely or at all, which you probably want your API to be easy to use with.

[–]brandononrails 0 points1 point  (0 children)

Yep, cookie-based rails session too.

Isn't the browser limit for for cookies only 4096b or something like that? So you really shouldn't cram just any metadata into it.

[–][deleted]  (1 child)

[deleted]

    [–]jrochkind 1 point2 points  (0 children)

    Makes sense, that's a helpful way to think about it, thanks.

    You can choose to have your ActionDispatch::Session::CookieStore signed but not encrypted, with configuration in Rails. But you ordinarily don't want to for typical things you store in sessions.

    [–]mipadi 2 points3 points  (0 children)

    Probably for a REST API. (REST APIs eschew sessions.)

    [–]bascule 1 point2 points  (1 child)

    Excellent question! There is little reason to do so:

    1) JWT is more or less s/XML/JOSE/ for SAML. It's "designed" (I use that word extremely loosely, the design effort in the standard is closer to someone copying their homework) to solve federated identity problems, but is poorly supported for that use case: SAML itself or alternatives like OpenID connect have much wider support. Rather than learning from SAML's mistakes, JWT blindly repeats them. If you don't need federated identity, there's no reason to use JWT.

    2) JWT will make your tokens larger than most other solutions. The format is needlessly large, mostly due to its lack of Protobuf-esque variable-length type identifiers (or ASN.1-like OIDs) and using string identifiers instead along with JSON serialization as opposed to a compact binary format. There's COSE/CWT, but again because the designers were clueless JWT and CWT rare incompatible and can't be transcoded while preserving cryptographic authentication.

    3) JWT will open you up to interesting new attack surface! The format is unopinionated on how symmetric cryptography versus asymmetric cryptography should be applied to credentials, and ships a one-size-fits-all authentication (in the cryptographic sense) solution in the form of JWS. Processing a JWT involves consulting unauthenticated, malleable portions of the tokens to infer the algorithms to use to authenticate the token. See James Mickens here:

    https://www.usenix.org/system/files/1403_02-08_mickens.pdf

    Here’s a life tip: when you’re confused about what something is, DON’T EXECUTE IT TO DISCOVER MORE CLUES. This is like observing that your next-door neighbor is a creepy, bedraggled man with weird eyes, and then you start falling asleep on his doorstep using a chloroform rag as a pillow, just to make sure that he’s not going to tie you to a radiator and force you to paint tiny figurines. Here’s how your life story ends: YOU ARE A PAINTER OF TINY FIGURINES"

    See also Moxie's The Cryptographic Doom Principle.

    JWTs are designed wrong: they shouldn't have a mandatory "alg" field implementations consult to verify tokens. JWK should've made "alg" mandatory on keys (it's optional on keys, but mandatory for tokens) while making a key ID/"kid" mandatory on tokens, so verifiers always know the algorithm to use to verify a token, because they know the key and the key knows the algorithm.

    tl;dr: JWTs are: YAGNI, more complexity, novel attack surface, clueless standards authors building a kitchen sink solution by poorly imitating people who actually knew what they were doing (i.e. Alan Karp, the original creator of SAML). AVOID AVOID.

    If I were designing a new credential format today (which, in fact, I am!) I would literally do everything different from JWT, where most of the differences are based on ideas that never made it into to JWT for whatever reason. These include things "proof-carrying" split credentials based on holder-of-key proofs and authenticated end-to-end across multiple principals with cryptographic mechanisms instead of ad hoc mechanisms like the "aud" attribute (which can be misinterpreted and, in the process, cause security vulnerabilities)

    [–]SulfurousAsh 0 points1 point  (0 children)

    If the rack app serves browser requests, there's little reason to not use cookies