We talk about all sorts of tokens: JWT, PASETO, Protobuf Tokens, Macaroons, and Biscuits. With the great Jonathan Rudenberg!
After we recorded this, Thomas went deep on tokens even beyond what we talked about here.
It’s the language that has an intelligence of a two-year-old because all it does is say yes or no to every question.
This rough transcript has not been edited and may have errors.
Deirdre: Hello, welcome to Security Cryptography Whatever. I am Deirdre.
David: I’m David.
Deirdre: And today we have another special guest.
Jonathan: Hey, I’m Jonathan Rudenberg.
Deirdre: Yay. Welcome.
Thomas: Jonathan Rudenberg you should tell us a bit about yourself.
Jonathan: I have been working on various software engineering projects for many years now. the most recent project I worked on was Flynn, which was an open source platform as a service. And. I built a bunch of that. And I also built all of the authentication systems for the system across a bunch of services that were potentially running in different places and had a lot of different clients.
Deirdre: That is extremely useful because today we are asking why JWT tokens? Why do people still use them? Why are they a pile of shit?
Thomas: And we, uh, we begged Jonathan to, uh, to join us for this episode, I think,
there’s probably an expectation that we’re, uh, we’re going to trash JWT and I sure. Well, um, but I think also some of us have surprising opinions about JWT.
Deirdre: Yeah. I mean, we have reasons to trash JWT, and yet everyone who is trying to build some sort of web service with authentication seems to keep reaching for JWT. So who can tell us what JWT stands for? Like the acronym,
Thomas: None of us know it
Deirdre: JSON web tokens. That’s what it stands for
Thomas: establishing our credibility right off the bat
Deirdre: Number one, the JWT stands for JSON web tokens and spoiler.
The name in the detail tells you a little bit about what’s going on, which is just, it’s kind of a blob of JSON that tells you. What your signature algorithm is, what your key type is, and some other metadata but you can maleate it. And one of those signature types, one of the signature algorithms that you can define in your JSON web token is ‘none’, which is bad, but that’s not the, that’s not it.
Thomas: I feel like, first of all, um, as always I’m probably wrong. and I’m also tipping my hand a little bit, but my general take on what JWT is, web frameworks have had for more than a decade now they’ve all pretty much have some kind of signed cookie. They all have a notion of a session and a session is a bag of attributes.
It’s your user ID. It’s like the last action you took. It’s whatever random crap people want to remember about requests and, frameworks have all for a long time, wanted to do something close to stateless, authentication for that stuff. which is just to say that, um, you want to be able to stuff all that stuff in a cookie, sign the cookie and then not have to remember it in the database.
there are really simple reasons why people want to do that. Like, uh, adding new bits of information requires database migrations, which are a pain in the ass to do so. Like it’s easier just to stuff something in your session and then remember it and assign cookie. So rails for instance, has message encrypter and messaged signer or whatever they call it.
And that’s, to me, JWT is essentially a, of the interoperable version of, message encrypter or whatever Django does, or, Fernet from, the Python cryptography people. It’s just like a cross-platform version of that with extensible cryptography. And that uses JSON as it’s, format,
Deirdre: You say extensible cryptography and my 🚨awoogahs🚨 start going off.
Thomas: we’re all being very calm about a bad situation here, but
Thomas: did I get any of that wrong? Do any of you disagree with my kind of summary of what, what JWT is there?
Jonathan: I think that I would disagree a little bit in that it’s you can just stuff, random stuff in a JWT token, but for the most part, it is usually used to convey some kind of identity, usually a username or a user ID, and then maybe some additional metadata. and there are some specifications like, open ID connect OIDC that also have definitions for specific fields that would go in the JWT.
But in general, my experience of it is that it is not as used as commonly to convey just like arbitrary data in the same way that the rails message encrypter stuff would be. Yeah.
David: it’s also not quite JSON it’s three different Jason blobs that are then base64 encoded, and then separated with periods. so, when you’re actually parsing them, you have to split out the periods, then decode the base 64 URL encoding URL-encoded of base64. And then you get three different JSON blobs
Thomas: it’s true that like, you know, JWTs are usually
David: sorry. I misspoke to cause the last blob is, is the signature.
Jonathan: And you have to decode so that the header is the first blob and it, it has the algorithm that is being used. And you have to decode that in order to use the token, unless you specified a static profile for the token, you have to do that before you check the signature.
Thomas: I guess I just start with like, what do we think the same applica— forget, JWT, the standard or its implementations or all of that chaos for just a second and just sort of stipulate that JWT was okay. What are the same kind of scenarios in which you’d want to use this thing? Like why do we have it?
David: Oh, right. Like you, like you said, you want a session storage. You probably want it to be stateless or almost stateless. We can talk about revocation and one, you should be checking state on these things later. but you want the session token. You want it to know that you issued it, you want authenticity or availability, whatever we’re using to describe that property nowadays, you want integrity.
You want to make sure that the thing you issued is the thing that you got back, that nobody added other stuff to it. You, in some cases, maybe you want confidentiality, I don’t quite understand why you would want that. why you would want to hide the data that you’re putting in the session from, the person you’re giving the token to, And then in other more complicated cases, you might want these tokens to be verifiable by a third party, or even if not a third party to be verified by a separate service, say you have, you know, example.com and you have log-in dot example.com. You probably don’t want to share an actual like secret, between those two apps.
You want example.com to use public information, to verify something from your login server in an ideal world, or maybe you don’t even run your own login server, right? You’re using a third party as your identity provider in that case, you’re definitely not sharing secrets. so you might want these to be, verifiable, using only public data and not, shared secret.
Thomas: guess until you get to that public data, you’re still talking about things that, rails message encrypter or Django sessions already give you, right? Like I guess I’m still a little mystified as to how JWT took off the way that it did. You might be able to blame OITC for it because OIDC for reasons, passing, understanding, baked JWT into the standard, O I D C itself a pretty simple idea.
Like you’re about to disagree with me, which is great, but, uh, my, my take on it is that OIDC had a very small problem to solve, uh, over OAuth and, you know, bit off 10 other problems that didn’t need to solve.
Deirdre: My feeling was that it was, there was an RFC for it, and there was no real RFC for any other like general interop web token. And so it just sort of won and just kind of built momentum, built multiple implementations in languages and frameworks. And then. There was no strong competitor.
That’s my feeling, Jonathan,
Jonathan: I completely agree. I think it’s just an IETF snowball in that there is a specification and therefore we must use it.
No, thank you. The JWT libraries exist, and if you hard code in effectively, a static profile around them in your own application layer code, where you always know this is going to be the public key, this is going to be the name of it. This is going to be the algorithm and you reject everything else.
They’re definitely possible to use safely.
Deirdre: Yes. If you hard code your— like the parameters of what you’re trying to use, if you hard code your algorithm and the types of keys that you’re using somewhere, and everyone uses that, then you lose a lot of the sharp edges of JWT. But if you don’t, it’s got a lot of sharp edges and like kind of what David said before.
the last time I had to roll out JWT, it was basically trying to do this sort of work with a third-party service that we did not control. And. it kind of infects basically, anytime you’re trying to interop, what are you going to decide on? Oh, well we support JWT and they’re like, Okay?
I guess we have to build in support for JWT here.
And then if we build it in here, then like, if there’s another thing that we have to interop with, down the road, then it kind of infects that one and so on and so on. And so on.
Jonathan: Yeah, and I think that’s the scariest part of it is because you end up using it in places where maybe it wasn’t as planned, you end up with. Other services that you don’t control using it. And they don’t necessarily have the same level of static profile that you may have applied in the first implementation of it.
And so if you’re not extremely careful, you end up in a situation where you are vulnerable to these pretty well known attacks. You’ve got type confusion. You’ve got this ‘none’ algorithm and, there’ve been other issues around just the actual implementation details of each of the libraries.
David: you explain what those actual vulnerabilities are in more detail?
Jonathan: yeah. So the type confusion attack is where you end up using a token that you’re expecting to have, say an HMAC. token, which is symmetric and with a secret and the verify function you pass the token and the secret in, and the verifier will just kind of blindly check that. But if an attacker swaps the algorithm in the header of the token for example, actually, sorry, it’s the other way round.
If you have a token that you’re expecting to verify using RSA, you would pass the token and the public key in to the verifier. And then, an attacker can change the header to be, the HMAC algorithm. And you end up passing in the public key as the key and the public key is known.
So you can end up with a token that verifies using, the wrong algorithm effectively.
Thomas: There’s, there’s
Deirdre: mean, terrible.
Thomas: there’s an even simpler version of that, where. Again, for reasons, completely passing understanding of their— JSON web tokens.
Their whole reason for existing is providing some kind of cryptographic authenticity for tokens. but one of the algorithms is ‘none’. you know, there are systems that accept tokens where the header has been swapped, so that like, oh, the algorithm we’re using to, uh, authenticate this as ‘none’. And there are systems that, trust it.
So for instance, you have a namespace inside of these JSON blobs for metadata for the token. But if you look at a lot of that code, when they have a construction like that, when you have the ability to just like, here’s a bag of attributes and you can put stuff in the bag of attributes, it’s not at all rare to find code where it’s like here’s user input, marshall, all the keys and values from that user input into the bag of attributes.
And that’s problematic when that bag of attributes has, you know, things that have semantic meaning in them. THere are other problems: expiry in revocation that are optional and weirdly specified. And I’m, I’m probably not capturing all the things that are going wrong with JWT, but.
David: you have a unique perspective on this because you did, you know, pen testing and vulnerability research and consulting for awhile. But at least in, in my experience, I don’t see a lot of people putting arbitrary data because it’s JSON into the token versus like the one or two fields that are either required by the provider that they’re using, or like the bare minimum to say, like user and group type, identifiers.
Thomas: I guess I see it. Yes. Two different ways. Right. And there’s a way in which it’s used where I don’t have as much of a moral objection to it, which is it’s the interoperability layer for doing, you know, signing with Apple or signing with Google or something like that. Right. where you’re just implementing exactly what the flavor of, OIDC and JWT that they’re asking you to do to get that feature working.
And then there are the people that have drunk the Kool-Aid and are using J JWT because they want, stateless authentication and more, more broadly stateless sessions. and. Like a drum I beat a lot as how underrated simple, random tokens are for this stuff. I, I’m not, I’m not totally bought into the idea of— look for, third-party dependencies when you’re trying to get, sign in with Google working, right.
Like, fine. Obviously that’s gotta be stainless somehow because you don’t share a database with Google. Right. But in real ensemble systems, even fairly complex ensemble systems statelessness tends to break down anyways. Right. I think it’s, overrated in that at some point you’re always introducing some kind of database backstage somewhere anyways.
and you’re not winning anything from adding the complexity of stateless tokens when you do that, but you still have people kind of using them as a general session store. So that is a thing you see, and you see it in places where people are using JWT. Because it’s a cool cryptographic tool that they like, feel like cookies plus they’re cookies plus, right?
Like they’re the better cookies. there’s a whole species of security commentary about don’t use JWTs and localStorage, uh, session tokens for all the reasons that localStorage is less secure than cookies. So I do see stuff like that.
Deirdre: Specifically localStorage in the browser, right.
Thomas: Yeah. Yeah. guess the point that I would make is, when you’re doing interoperability with other systems that the most mainstream way of doing federated authentication of SAML, which is the worst cryptographic protocol on the internet, there isn’t a worst one. Right? So at the point where I accept that you’re doing SAML, I, I obviously I don’t have a leg to stand on to say that you shouldn’t do JWT.
SAML is in every possible way, worse.
David: Is SAML. I don’t know if SAML is more common or not, but I feel like there may be a crowd of people that want to use JWTs cause they’re you think they’re the Uber awesome token. maybe these are the same people that just want to roll their own crypto anyway. And they’re the people that we talked about, who aren’t going to listen to us at all.
Um, in the previous episode, with Filippo, but,
Jonathan: I’d argue that it is not rolling your own crypto to use so JWT though it is the only off the shelf solution that will just work.
David: Yeah. And the alternative is actually usually rolling your own crypto when like signing a protobuf. But I guess where I was going with it was, I feel like most people are using them because they’re speaking OIDC, like I think, OIDC it’s not just that JWT is a standard, it’s that OIDC unlike regular OAuth, specifically says you have to use a JWT and here’s how it’s going work.
and, and, and that is how, yeah, you do sign in with third party services. And that is how, when you go to Auth0 and you buy their, user products, they’re using JWTs, they’re the people that are running the website, jwt.io that is encouraging people to use it. At the same time they have an algorithm: ‘none’ vulnerability, like once a year.
uh, I think they they’ve had what, three of those now. And they were bought for $3 billion. So I guess that’s $1 billion per
Deirdre: with a B oh my
David: They were bought by Okta. So if we had a competent SEC, the acquisition probably wouldn’t have gone through. like that type of integration I think, is what’s driving the adoption here.
It’s it’s OIDC third-party services. and again, like, you don’t really have another option there.
Jonathan: I think that there is one interesting point about using for OIDC, which is if you’re just implementing the simple sign-in with Google flow, you don’t actually need to do any of the JWT things. You got the token over TLS from google.com. And so you can just decode the middle segment, which is the JSON blob that contains the username.
And you can just use that and you don’t have to like, do any checking of the token. In fact, when you add in, oh, am I going to use the certificate from the discovery document and all of this, like more complex stuff, you introduce more risk into your system.
David: do we want to talk about how OIDC works? Do we want to talk tokens first?
Deirdre: want to know more about OIDC because I, I rolled out JWT in some systems and it did not have any OIDC in it. So I would like to learn more.
Thomas: Can I take a stab at defining OIDC that will be wrong. And then we we will all learn from you guys correcting me. So in the beginning there was OAuth, right. And OAuth is a way for me to post tweets on your tweet stream. Right. seriously, that’s like the idea it’s like, it’s, delegated access to some sub resource of an application.
David: It’s doing things on behalf of someone else.
Thomas: And people quickly realized that if you can do that, that you can use the delegation of some resource to prove that you’re a user, right? So like access to your Facebook account details or your username, or somewhat that on Facebook, but that’s been delegated through OAuth.
You can use that to prove that this person has a token that gives us access to his Facebook profile. So ergo, that person must be that person. Right? And it turns out that breaks down pretty quickly, right? Because, delegated access to a resource is not the same as your identity. People don’t use it the same way.
So there were all sorts of vulnerabilities where people were taking, benign looking OAuth tokens and using them as identity tokens for dumb services that had tried to implement like login with Facebook that way.
David: you mean that like, I, Facebook user, did an OAuth to let somebody like post on my wall. Cause it’s 2009 and walls still exists. And then someone takes that OAuth token and then, uses that to sign in as me, the Facebook user on a different site? Like what,
Thomas: Yeah, I think.
David: what was going on there?
Thomas: I think like I’m off on the details. I’m sure. Cause I don’t have it in front of me, but it’s, I think it’s basically that, right. It’s like, access to post on my wall becomes a bearer token saying I’m this user. And then there are systems that trusted that. And so the idea behind OIDC is that it’s like a profile of OAuth.
It’s the same OAuth protocol. but as like a profile of OAuth that embeds tokens and those tokens have like rigidly defined meaning that like these are bearer tokens for authentication. These are intended to prove that you’re a specific identity. you can imagine implementing that without any of JWT, I think, right?
Like you would just need some kind of well-defined, definitions of what fields are and what like, scopes mean or something like that. Right. you probably don’t need an extensible bag of, cryptographically authenticated attributes, but that’s my understanding of what OIDC is.
David: I mean, you need, after the code exchange, you need a defined thing that has a defined field in it that says this is my identity. And then it’s verifiable by third parties. Right? Like that’s what you need at the end. You
Thomas: An OAuth token sort of already has that in the sense that they’re already scoped.
Jonathan: I would say that it doesn’t need to be verifiable by third parties, per se, if you are the relying party and you get a token over TLS from the identity provider, you know you got it from the identity provider. So it doesn’t need to per se be third party verifiable. OIDC has this property where the JWTs are third party verifiable in most cases.
And so you can actually get up to shenanigans with them. And I’m just not convinced that any of those shenanigans are actually a good thing.
Deirdre: What if you are a very large provider, like a Facebook where you have a bazillion certs you may have multiple certificate authorities issuing those certs. how do you ensure that if you are just trusting the fact that you connected to someone who you can verify their certificate chain all the way down to a certificate authority root cert?
that that’s the one.
Jonathan: I mean, secure your auth service properly.
Thomas: but isn’t this how everything goes wrong on the internet at all, ever like isn’t this, the original sin here is, what, if you were Facebook and you have this complex topology that you needed to support, right? and there’s a standards discussion where we’re discussing, okay. We need to add some kind of, metadata to an OAuth token to say it’s an identity token, but what about all these other scenarios that Facebook and Google have?
you know, make sure that the standard captures every possible wrinkle of how they’ll do it. Nevermind the fact that they are Facebook and Google and they will ignore the standards anyways, they have better implementations of all of this stuff. They’re much more familiar with their own topology than the IETF is or whatever godforsaken standards group came up with, you know, whatever.
Right. in the end, what happens is that right? You end up with, you know, smaller organizations that should be exploiting the fact that they’re not Facebook, right. That they don’t have any of these problems. but they’re dealing with standards that are kind of. I don’t, I don’t even know that Facebook and Google look at these things and say, well, this does a great job of capturing what we’re trying to do.
This is absolutely best practices. I mean, maybe this is the, these are the organizations that brought us Kubernetes. Right. So it’s possible do you think that way? Right. But I guess not right. I guess that it’s just. It’s kind of like a grotesque monstrous version of what they’re trying to do.
That’s been filtered through standards bodies, and then the people that are on the receiving ends of these things that are actually putting them into practice, don’t have any of the context for why these things are that way or what the pitfalls are to doing that. So like Jonathan you’re describing scenarios that are kind of sane where it’s just like, I’m trusting TLS, I’m in direct communication with the IDP.
That’s, you know, that I’m relying on to, sign somebody on it and that’s the end of it. Right. I just like, I need to get the user ID from this TLS connection to this trusted IDP. Right. But the token asks you then, well, do you want to build a bunch of backend systems where you can pass that token on and they don’t need access to the IDP to verify this?
Sure. I mean, you could just build your own inner services, authentication thing, and you would have a much better idea of how that works, but instead you could make the JWT standard. Do all of that for you.
David: Jonathan, could you explain, when you do or do not have to like trust TLS within OIDC?
Jonathan: So if you are the direct RP, the relying party for the transaction and you
David: relying party is like the app, so it’s like
David: I’m app.com and I’m trying to use google.com as my identity provider to sign in a subject who was the user? Correct.
Jonathan: Precisely. And in that case, you can just fetch the token over TLS as the last step of the OAuth to IDC process. And you can just throw out the header and the signature and just decode the base 64 in the middle. And you have JSON that, you know you got from the right place. it becomes is much more complicated if you decide to reuse that token for other services.
In that case, you need to check the signature, which means you need to fetch the keys that were used to sign the token and have a system for refreshing those and, discovery. And you end up with potential vulnerabilities around not only the headers and the design of the tokens, but also around what’s in the token itself and how you’re using it.
Right? So a token is not scoped correctly to your service. Someone could get a token from another auth transaction or potentially on another service that was meant for something else, and then just pass it in and use it to authenticate within your service, unless you’re very careful with how you’re using them.
Deirdre: So, what about not JWT?
Thomas: I think like before not JWT, like I I’ve been, I’ve spent the last several years reading cryptography engineers kind of slagging JWT. So like there’s a practical case for using JWT, the obvious practical cases. It’s the way that you implement sign-in with Google and sign-in with Apple and all that, fine.
But for systems where you don’t need it, you know, for systems where you have some design flexibility, what are the things that JSON got right? Because we can rattle off things that JSON got wrong, right? Like, Sophie Schmieg was on Twitter the other day, kind of with a thread and it’s a thread I’ve read from a lot of other people too.
And I feel like it bubbles around, but it never kind of breaks through, into the mainstream, just core design flaws, of this protocol or this token format. Right. The number one has to be that it’s a token, it’s a, it’s a fairly complex token, you know, compared to other tokens, where you have to parse it to understand how to verify the authenticity.
what else? Cause there are other things that are wrong with this.
Deirdre: And to because I wanted to bring up Sophie, uh, before, because I love her. if you’re ever going to design a thing, anything like this, again, take the properties of the keys with which you are verifying stuff and bind them together. she gave a very good talk about this at, uh, Real World Crypto at some point in the past two years, where that literally it’s that, if you have a key whether what kind of key and what algorithmic parameters, and like, if it’s an elliptic curve, public key or whatever, what curve it is, are all bound to the key so that you can never accidentally use an HMAC and try to turn it into an RSA kind of like the example that Jonathan was giving earlier.
that is not what happens in JWT, but Yeah. What else.
David: well, there’s the fact that like encoding, this can and can not be a problem, but like, encoding JSON isn’t well-defined what order did the fields come in? all numbers are floats. but sometimes they’re also strings, what’s your JSON decoder gonna accept versus what’s it gonna spit out versus what was actually there and you expected.
It’s just a very weak format and weak formats tend to be harder to use. In anything that’s being cryptographically verified, unless you’re very careful on how you do it and you have to keep the decoded version around, verify that then decode it, afterwards, which you’re encouraged not to do here because you have to parse the header.
Thomas: Jonathan you’re on the CFRG mailing list. your job has required you to answer questions on CFRG because you’re cursed, and somebody brings JWT to you for the first time, and you’re going to do your best to stop it from being a terrible, terrible cryptographic standard.
What else are you going to tell them not to do?
Jonathan: mean, I think that having the algorithmic flexibility in there is a bad idea. Like you have to just pick the exact specs, you offer a token and have that, out of band with the keys, not in the token itself.
Thomas: I have a spicier take on that, which is, and this is a place I think all three of you might disagree with me, but I see it as kind of a design smell. When I see any kind of format where there’s selectable public versus symmetric key encryption, where there’s, a mode where it’s deployed asymmetrically and a mode where it’s deployed symmetrically.
Like same format, but you can use it both ways. To me, those are radically different deployment environments. They’re basically different protocols. So at that point, they different security properties. You manage them differently if they’re just not the same thing.
Thomas: And in addition to kind of the flexibility, you have to pick algorithms and you know, how that’s not tied to keys and all that.
There’s also just the fact that JWT tries to be these multiple different things. there’s again, it’s back to, like, there are sane ways to deploy JWT because you have to for Google, but that has one profile that it’s deployed in and it’s a common profile. It’s the way that people ordinarily do it.
Right. But it supports all these other deployment modes that just beg people that use them. and you know, it’s not specialized any one of those things. It doesn’t do a good job of any of those things. am I wrong about that? I think you could make a case that I’m
David: think you’re absolutely right about the whole symmetric versus signatures thing. And to compound the problem with JWT and nearly all of the docs that you read about it. It still refers to HMAC-SHA256 as a signature algorithm, which is deeply frustrating it’s not. and then like, I don’t know if you’ve had this experience, but a conversation of like web developer going, Hey, we’re introducing JWTs and we’re going to use.
Here’s why we need to do it because of, you know, reasons I discussed earlier. And then, you know, we’re going to use like HMAC as our signature algorithm. And then I go, that’s not a signature algorithm. And they’re like, well, it’s in the docs. And then like, now you’re just arguing over something that like, you didn’t really want to have that argument.
that’s not the thing you wanted to explain to somebody else or to like, that really limits the correctness of the deployment. It’s just, we’re talking with different terms now we’re already off base and we haven’t even gotten to what does the deployment look like? I think I’m even stronger against that on you just cause I’m so annoyed that they, they call it.
Deirdre: Yeah. And just to quickly give context, we’re talking about a signature as an asymmetric public private key signature, such as EdDSA, ECDSA, and RSA, whereas a MAC or an HMAC is a message authentication code that relies on a symmetric shared secret to verify. So that’s the, that’s what we’re talking about.
Thomas: Kind of additional fun times for JWT here are in addition to the fact that it has a mode of deployment for symmetric and the mode of deployment for asymmetric, within asymmetric, you have multiple options for how you’re doing the signatures. One of them is P-curve elliptic curve. there were, I think three or four years ago, there are a bunch of vulnerabilities found in implementations where, the P curves are the NIST standard curves that the U S government kind of promulgated, curve standards.
They’re fine for what they are,
Thomas: but they were designed in like the early aughts, I think, sometime around then, like they’re a form of elliptic curve, with kind of an older curve equation, where, when it was designed people weren’t thinking about directly attacking primitives, the way that they do now.
so now we have a notion of misuse resistance in the primitives that we we work with. Right? So we try to adopt primitives where, there aren’t very many foot guns there. Aren’t a lot of things you have to check for. You just get a lot of security by default and the P curve standards. Aren’t that?
Um, so when you, are,
Deirdre: However, we get better equations now.
yeah, I’d Like I bet they’re all implement. I bet there’s a bunch of P-256 curves that’re being used in JWT implementations that are still using 15 year old, short Weierstrass curve implementations that are like a ton of if-then exceptions for like, if you know, your curve math, isn’t working out, which is not easy to maintain.
Thomas: you can kind of visualize in your head like a curve. It doesn’t even have to be the right shape. Just imagine a curve in your head and imagine like the X, Y Cartesian coordinate plane that that’s plotted on, right. When you’re doing the math on the curves, you’re dealing in terms of points that are ostensibly on the curve itself, right?
So there’s a line drawn through this two dimensional space that is the curve. And you’re only meant to be dealing with X, Y coordinates that are on that curve. But obviously the Cartesian space gives you like the 2d space that you’re working in. you can put a point anywhere in space. It doesn’t have to be necessarily on a curve.
Right. and the problem that you have with, a bunch of, uh, of P curve
David: fact, most points aren’t on the curve.
Deirdre: Correct, because we’re only over a finite field and there’s a whole bunch of points on the regular curve that they’re not in the field.
Thomas: Right. And so you have this problem with like a thing you have to check When you’re dealing with P curves is, when somebody gives me a curve point because it’s baked into a public key or something like that, I’m mangling this. Right. But like, when I’m given, a curve point, I have to check to make sure it’s actually on the curve.
If it’s not, I can’t do anything with it. I should just drop the request on the floor. it’s totally broken. Right. If you don’t do that check, you wind up revealing information about your secret key in the response that you generate.
Deirdre: Well, if you compute over that point without checking to see if you should reject it, right?
And so that attack is kind of known as an invalid curve attack and like the number of things that have to go wrong in a token format to have that problem. it’s more than just using the P curves. and it’s, it’s more than just encouraging people to use the P curves. And it’s more than not checking to see if you have an invalid curve point. In addition to all of that, you also have to be deployed in kind of a static-ephemeral mode, where there is a single static secret that you attack. Right. So like, in the normal case, when you’re doing kind of elliptic curve diffie-hellman, if you tell me you’re working with ephemeral keys on both sides of it, so there isn’t much to learn about the target here, necessarily something to learn about the target key that you’re attacking, because that key is just local to your session.
Right? So like, you can learn something about it, but it’s gone in a second, right. But, JWT implementations were deployed in static-ephemeral, you know, elliptic curve Diffie-Hellman modes, where there is a long-term target secret. You could submit multiple requests and learn a durable secret that you could then target, right?
Like to have that mode of deployment to make it possible, to deploy that way. It’s like you put a kick me sign on the whole protocol. Um, so it’s an extended rant on a point that,
Deirdre: It’s like, try all your attacks against my static elliptic curve secret. Yeah.
Thomas: it is kind of like the Thunderdome of, uh, of cryptographic vulnerabilities. I sort of enjoy it a lot more than I do, but.
Jonathan: I mean, going back to your original question, Thomas. If I got a spec for that, with the ‘none’ algorithm, I wish that I could just say like, no, just go away. Like you’re doing everything wrong. If you have a ‘none’ algorithm in the initial design of your system, like there is no scenario where that will help anything.
Deirdre: It’ll help testing for the broken thing. It’ll help me test the broken thing, which is easy for me as a developer and hard for any security engineer.
David: I don’t know, having implemented TLS before, I think of the NULL cipher, supporting that actually makes things harder to test,
Deirdre: Oh Jesus Christ. I forget.
Thomas: wait how does, how does the NULL cipher make TLS harder to test?
David: Because you need to like build in that code path versus, versus always pushing through some sort of. Like symmetric crypto. It’s not as bad if you already have some amount of agility in it and you’re just using it to test, but like, the existence of the, NULL one implies that like, maybe my nonces aren’t fixed length in every message, maybe I can’t hard-code that parameter anymore.
Maybe I can’t hardcode this other thing anymore. and so depending on how much agility you’ve put in already, you might already be in that spot at which point, like, okay. maybe ‘none’ does let you debug something, but likely it makes you take a bunch of things that would have previously been hard-coded constants, um, and are now look-ups.
Thomas: So we were going to talk about alternatives to
Thomas: I hadn’t had enough time to pummel JWT. So
David: Well, want to add in like the, the positives on it though, again, are that— you have two services in two different languages that need to verify these things and you don’t want to roll your own, signature format. like you’re kind of in a JWT world and you’re probably better off using those with a static profile than you are.
trying to come up with a different format. especially if you don’t have someone who does cryptography engineering on your team, and like, if you are doing OIDC, like that’s what you’ve got. And you know, you have to deal with what you have to deal with. on a lot of cases, you can treat the JWTs as just opaque tokens, on your end.
which again, then, like, who really cares if it’s a JWT, if you’re getting handed a JWT, but you’re just storing it as a binary blob who cares.
Thomas: so like if the only thing that you’re trying to solve is, interoperable format for a bunch of different platforms, right? you have some alternatives, some of which have a lot of the same ergonomics as JWT. I think like the, the best known there is probably PASETO? you guys might know PASETO better than I
Deirdre: Yep. oh, it’s been a minute. I think we’re on
David: Seto? Placedo
Deirdre: I always said Pah-SET-oh yeah.
Thomas: I watched an Okta screencast about PASETO before we started recording this. And they said pah-SET-oh. So from now on it is PASETO by the way, I don’t know why it’s not just PAST. Right? If look at how the acronym actually expands, it’s like platform agnostic, security, token. Okay. It’s PAST, but whatever it’s PASETO
Deirdre: It basically is trying to shave off some of these sharp edges from JWT and just kind of give you very specific parameter sets. And like We either pick like the symmetric one or the asymmetric one and there’s no, ‘none’, you get no choices. like you have to version.
You do use a different version of PASETO version one, version two, version three. I think we’re up to three now. And that’s how you get the quote unquote algorithmic flexibility. the cryptographic flexibility. And that kind of goes along with the patterns we’ve learned from things like TLS and Wireguard and other places where you should have one joint and keep it well greased.
And that should be versionable. You shouldn’t have a smorgasbord of cryptographic algorithms and choices and parameter sets to choose from all in one go, if you want to change them, you have to change the version of the thing that you’re using, which only gives you a couple of options.
Thomas: I’ll read the room here. How do we generally feel about PASETO?
Deirdre: Like when I was trying to build stuff and people were like, well, JWT and I’m like, what about PASETO? if you want to use JWT, PASETO basically gives you everything that you want without all the crap that you don’t want, except for the fact that it’s not baked into, you know, open ID connect or, all those other things.
And there are fewer libraries, but there’s still quite a good, a few libraries in different languages.
David: Before I state, my opinion. I want to make sure that my understanding of how they work is actually correct. Um, how very responsible of me. Uh, but so there there’s two main types of setups, right? There’s the local and the public, Deidre. What, what’s the difference between those
Deirdre: oh God, I’m pulling it up again.
David: like local is some kind of symmetric encryption.
I want to say AES-GCM
Deirdre: Yeah, there’s public and local shared key encryption, symmetric key, uh, authenticated encryption with associated data.
and only lets you use authenticated modes as with GWT, you get to specify algorithm. There’s only those two options per version. yeah. Does that help?
David: Looks like it’s uh, Chacha-Poly1305, which is an AEAD with a nonce where the nonce is a random byte string, then fed to Blake, is the nonce. And then I assume that like, they must have specified like the ordering of those bytes to be like, here is the nonce. Here is the encrypted payload.
And here’s where the, that auth tag is. payload itself,
Thomas: there’s like a V one of PASETO, that I thought it was like normie crypto. Um, it might be GCM and it might be HMAC. And then I think it’s RSA for the public version. And then there’s the V2, which is like the cool kids crypto, which is, you know, Cha-Poly and, you know, in Blake and all that stuff.
And, a good curve for the signature format and all that. I don’t know the history of it, but to me, they kind of, all this stuff appeared at the same time. So there was like V1 and V2 or V1 exist for people that can’t use cool kid crypto. and then there’s local and public for, again, this kind of idea that we needed a token standard for both of these things.
And they’re basically interchangeable with each other. Um,
Deirdre: you’re correct. V1 is 2048 bit RSA, and authenticated encryption uses, AES counter mode with, HMAC SHA-384, for the tag.
David: Well, the nice thing about using like the aeads for the local symmetric mode is that you can, you don’t really have to worry as much about the like type confusion because you just feed. The header that you got in as associated data, which I believe is what they do. And then, you know, if there’s a mismatch, it just doesn’t work.
If you, for some reason to have local and symmetric tokens are local and public, uh, in the same app, maybe you’re going to have trouble, but you probably shouldn’t be doing that anyway, as we discussed earlier. so I do like that. but like, again, that the thing that confuses me about PASETO is just that the core issue with JWT was you have to like read off this header first and then figure out what to do.
And now PASETO, still have to read off this header and figure out what to do. There’s just only two or three options for what to do, but like that doesn’t get rid of the main problem. it’s just there’s one or two static profiles now that you get to pick from, not fix to the format.
Deirdre: Right. But that does seem to be like the way that you deploy JWT securely in practice is like, basically what PASETO does is like you lock down everything that you can lock down, except for the fact that you still have to read in this header and the way you are doing things is in-band, not out of band.
David: Well, yeah, but then I still have to lock down the header with PASETO. Right? Like hopefully things go wrong less with it. I’d have to like dig into the details of which keys are used, where and, and so on. But like, I, you still have to make that decision, ahead of time.
Thomas: there’s a thread on CFRG— CFRG is the cryptographic research group for the IETF or for IRTF or whatever they call it. Right. But it’s all the cryptographers that are involved in standards. Right. And I think back in 2018, the PASETO authors, um, submitted Pasetto to CFRG, which first of all, kids never do this.
there is no conceivable upside to submitting a new standard to CFRG for any reason ever.
David: just let someone else do it. back in 2015, I published this paper with some of my grad student. co-authors Zakir Duromir among other people about email security and how STARTTLS is being intercepted and then Zakir presented this at an IETF meeting. And then four years later, someone else wrote a new standard and that’s the ideal way to do it.
We just showed up, measured a problem, said it was there, talked about it once and then let other people do it. So even if you do want something to be standardized, let the people that get paid to do IETF work for their job, which is a real role, many of these people have titles like principal engineer, at big tech companies, let them do it. it
Thomas: I paid virtually no attention to the CFRC at all until Trevor Perrin posted on his modern crypto list that, I think curve25519— it’s either curve25519, or ed25519 was submitted to CFRG or was discussed on CFRG. And they were changing curve25519. They managed to find an incompatibility to introduce into curve25519.
Right. is like, it’s literally the only possible outcome.
Deirdre: I, might’ve helped on that RFC.
Thomas: I don’t see a thing that can happen besides that. Right? Like either it’s going to do nothing either. Like they’re going to, oh, this is great. You know, proceed. In you learn nothing or they’re going to change something.
Deirdre: As someone who’s trying to help with an RFC draft right now. And I’ve been supposed to look at the latest edits for a week now. And I’m sorry. we kind of have to do it ourselves because there, there are other drafts for this application of cryptography. And if we don’t do the thing for our thing, these other things, will get there first and get standardized first and adopted first and we think they’re worse. So.
Thomas: I love this all so much. like I, I brought it up
David: It’s also like a quasi, like neutral way for big tech companies to negotiate with each other about interop. And when they already need to do interop without looking like they’re a monopoly,
Deirdre: Yes. Or a cartel.
Thomas: that’s the IETF in general, right? That’s still not CFRG.
Deirdre: Oh yes.
Thomas: CFRG’s only the downsides and none of the upsides, but like the PASETO author submitted, PASETO to CFRG. And like, there was a pretty decent thread there that was critically looking at PASETO.
And like, there were two big complaints and one of them is the one that you already brought up, which is just the idea that you’re reading a header and then deciding how to cryptographically handle something. And I think for the V.1 tokens, they had it back all the way to the type contusion bug, between RSA and HMAC which is crazy to me that you would come up with a new standard that has— it doesn’t as far as I know in V2, at least.
and like, there’s a note about it now for checking in V.1, but of course, JWT can add that note too. And then the other critique was just that PASETO is basically a reduced mode of JWT. You could also just specify, you know, a profile of JWT that only does what PASETO does.
Deirdre: But also better cryptographic options as well.
David: Aren’t those basically the same critiques,
Thomas: Are they
David: you’re reading a header and then deciding what to do, but we’ve shrunk it down to two things. Just statically, define what profiles you’re using and— those are just two sides of the same coin of like, we should just statically define what profiles you’re using to define reduce JWT.
Thomas: I’m pretty sure you’re better off with Paisano than you are with JWT, right? Like if you’re going to use something— like my critique is against the whole idea of JSON tokens to begin with. And if you need a JSON token, fine, PASETO’s better than JWT. There’s no question about that to me.
Deirdre: Speaking of which, there’s all these other things as What about Maca— is it Macaroons. Has anyone deployed this? Macron’s!
Thomas: Jonathan introduce us to Macaroons.
Jonathan: Okay. So macaroons are. they’re an authentication token format that has a couple interesting properties that none of the tokens we’ve discussed so far half first, there’s only one cryptographic algorithm that is used, which is HMAC. And two, they are extensible in that you can add additional constraints to a token after you’ve received And so if you issue a token and then pass it to a client, the client could then add additional constraints to the token before then using it or passing it to another, service.
Deirdre: That’s wild. And this is developed by Google. Was it, did they actually deploy it?
Jonathan: It’s a paper that was released by Google research.
David: and then just to clarify, what’s the benefit of being able to like, as a client, reduce the scope of your token and give it to someone else.
Jonathan: I think there are a bunch of benefits. The top ones are one: you can bind the token to the request in a clean fashion. So you could, for example, include a hash of the request, you could include, details about the, connection you’re sending it over. For example, you could pin the TLS connection, you could, just constrain it to a specific API end point and then pass it to another service.
Or if you’re worried about interception, like man in the middle, that kind of thing, you could constrain it in such a way that there’s less damage would be done if it was, if it was intercepted.
Thomas: Another cool thing macaroons do is, there’s a notion of, tokens that are linked to other tokens. the claims and the macaroon are called caveats. and they have a specific name because they’re like, it’s, it’s really kind of elegantly baked into the construction of the token, how claims get added and how they’re all authenticated.
it’s conceptually, it’s really simple, right? It’s just a chain of HMACs. So like the previous HVAC output is the key for the next caveat and you kind of, you can just kind of roll forward that way and add as many caveats as you want. Which sounds crazy when you think about it, like, you’re giving a user, a token with the ability to add arbitrary new caveats to it.
Like they can,
Deirdre: bound to the original thing, right?
Thomas: And also like the, there’s a semantic idea in macaroons that, the set of caveats that you have there, those predicates that you’re, you’re giving all of them have to be true. So by adding new caveats to a token, you can only be reducing the power that a token has.
but another thing you could do, like, most of macaroons just use HMAC, but there’s also, they use AEAD crypto to link together. So you would embed a key for a token and a reference to a token. And like the way that usually gets used, like the classic case for that is I can have a token that says I’m allowed to read and write this file name.
And I’m allowed to do that. As long as this token is accompanied by another token that verifies that I’m user Bob. so that’s, this idea of a third party caveat. And what that lets you do is lets you have like id.my service.com, that issues, those tokens, those discharged tokens that say I’m user Bob, that’s all those tokens say, right?
It’s like your user Bob. And now you can, you can kind of construct tokens that, kind of assert both here’s the things you’re allowed to do. and here’s the condition in which you’re allowed to do them. I have a lot to say about macaroons, unlike everything else where I have nothing to say about anything.
Um, in part, because I I’m a developer at a platform company, like we’re, a small number of engineers kept getting with all of AWS is a good way to think about my company. and we’re doing kind of a macaroon implementation for our authentication system. it’s, it’s super valuable for us to be able to take, you have applications running in our cloud and then you want to like have stats from them.
Like you want to hook them up to Grafana, right. The thing you don’t want to do is as a user, you don’t want to give Grafana an all-purpose authentication token that does anything you just want to give it access to, to, you know, to stats, to, Prometheus or whatever, right. macaroons express that really beautifully, can take, you know, your original, you know, godmode token and then turn it into a token that is only useful to Grafana.
That’s super powerful and interesting. Right? So biased. it’s another drum that I beat in is that macaroons are not used that often, but they’re not used often at all. We don’t really know anywhere where they’re like really commonly used. And, you know, this came up recently on a slack where I was talking to Jonathan about this and Jonathan, you, you have some takes on the ecosystem of macaroons as they exist in public libraries.
Deirdre: Are they spicy takes.
Jonathan: I mean, I would say that and why macaroons aren’t used widely is because none of the like public open source implementations of them are any good. think that the, and I think that the reason for that is macroons started as a paper. There is no specification per se. There’s just some ideas in a paper that as far as I know, like never were fully implemented anywhere.
And so some people came along and said, oh, this is a really cool idea. We should implement that. And they ended up with a system where the caveats are just a opaque blob. And the way that it usually gets implemented is the caveats are this, like text-based DSL that you have to parse and it’s embedded in the token and It’s just not really good at all. I don’t think, I think that it really hinders adoption in a way that in the same way that JWT is used everywhere, because it, it kind of works the same way. And you’ve got the exact same vulnerabilities everywhere. This is almost like you get some ingredients and they’re just, there’s not a good enough recipe in order to implement it well, and it is a lot of work for the developers to use the few existing open source libraries that implement it.
Deirdre: Yeah. You say text-base DSL, and I get the security parser wibblies from that.
Jonathan: Yeah. I, I think that you have to implement your own caveat system on top of any macroon implementation and using like just ASCII text for that is not the way to go. I much prefer a constrained format that is well-defined.
David: I mean, it’s more than like JWTs are used for like identity and maybe like a group membership on the regular case. Whereas, a macaroon, is really more about authorization rather than authentication. It’s about delegating, capabilities to someone else kind of like doing OAuth without having to do OAuth all the time.
Right. It’s back on the action side. So if you’re just trying to like, say, Hey, my name is David and I have an account on this web service and I’m in the admin group. there’s just no reason at all to be using macaroons because you don’t have any caveats, you know, you just have a very complicated token.
Thomas: Yeah, I think that’s fair. I think, um, Jonathan, I think you’ve implemented macaroons before, at least to play with. Yeah. And I’m, I’m in the thick of it right now. So I ended up like, I guess I’m going to credit this to you. I don’t know if I would have done this if I hadn’t talked to you about this beforehand, but we did our own complete soup to nuts macaroons implementation, like, as I’m sure you, you discovered right.
When you sit down to write macaroons, the actual macaroon construction is just completely trivial to implement. Right? It’s a very, very simple thing to, And like the public macaroon libraries have a sort of specification to them. Like they use some of the same encoding as protobufs, but not protobufs.
and like there’s an interoperable format, by the way. I don’t understand that all the reason to do interoperable macaroons in that nobody uses macaroons. So there’s nobody to inter-operate with. Um, so kind of adhering to a specification didn’t make much sense, but we also, we ended up using message pack.
We have, uh, a strongly typed Rust system of caveats, and then we have libraries that call Rust for it. which makes me feel kind of okay about it. And again, like, we’re kind of, the textbook case, like it’s like Google paper, for Google infrastructure and inner service authentication, which is kind of, we’re not Google, but like, you know, we’re a small facsimile of Google, so, um, yeah.
I think it does kind of make sense for us. And I, I don’t know if I would beat the drum as strongly for macaroons, having implemented this, I think like a weird thing you run into when you do this, is that getting your head wrapped around the macaroon model of what a, what a set of caveats means versus what a bearer token means.
Like with a bearer token, I extract the user from the token. Then I go to my database and I say, what does this user allowed to do through all my database associations and things like that. And that is not the macaroon model. The macaroon model is here’s a token. The only way this could have been issued is if the system said it was okay to issue this token cryptographically in the first place, just trust the token, just do it do what the token says you can do, it’s not exactly that, but like when you think about what the caveats are, you have to be careful.
Not just in terms of parsing the, the caveats themselves, which does scare the crap out of me. And that’s why we have strongly type caveats, but also just like semantically, what a caveat is, like a caveat has to be a restriction on things that you’re able to do with kind of a broader godmode token.
And that, like, here’s a caveat that says I’m also allowed to do X, Y, and Z things, right. At which point you’re, kind of screwed, right? Like, you’re allowing users to add things to tokens that could potentially change, you know, what you’re allowed to do with the system.
Jonathan: Yeah. So I think the canonical example would be like, how do I pass a user ID around with macaroons? And the answer is, well, you put it in the body of your message and you add a caveat that constraints that, field in your message to that user ID.
Thomas: I think the thing we’re going to end up doing is. All of our tokens, have a third-party caveat to an authentication service that is discharged, authentication tokens, and then we’ll take a user ID from that one signed, discharge token, you can’t extend a discharge token in the macro inspect.
Like once you get a discharge token present an additional hash at the end of it, that seals it off, so you can’t change it or anything like that. And so like, we’ll basically treat the discharge authentication token as a bearer token. you know, and I can pull metadata out of that, I guess.
Jonathan: Yeah. When I implemented it, I did explore that and I was much more comfortable just in that token, adding constraints on the message and then expecting the client to just pass in the pieces of metadata that you’re expecting to get out as part of the message body that the token is going with.
David: WIth all of these, like authorization systems though, like there’s more to it than just the crypto and then like validating the token. You still, no matter what you do have to write some authorization code that says, given all of the stuff that I hopefully just verified, can the user, with this role, do this action on this object.
I’m assuming you’re doing rbac. Right? someone has to write that and you have to implement that. there can be bugs in that, regardless of if there’s macaroons or not, you may have to parse the caveats in macaroons, but that’s just part of writing the authorization code.
Jonathan: I mean, if you’ve implemented macaroons correctly, that, can I do this as encoded, as caveats in the macroons? And so you’re not doing any permissions check as part of your authorizations. Like you have a macaroon verifier that gets a bag of data about the request, probably including the actual request body and then some metadata.
And then you’re running through each of the caveats in the bag of macaroons you got, because there may be a third-party macaroons, that are discharging, caveats, and you just run through and you check all of those. And if you come out with every caveat passed, then the authentication or sorry, the authorization of the request is complete.
David: Yeah, but you still have to like, define the service still has to know what it’s right. And then pass that. you still have to be getting a user ID in an action thing somewhere, even if it’s in the macaroon and then comparing that to what you expect, like you still have to make that call and gather the information about the world.
That is like, this is the me, the service is trying to do. Right.
Thomas: Sorta. So like, in our system, right? Like when I verify a request with a macaroon, I have the request. I have the organization that the request refers to. I have the application that’s running that the request refers to. I have the sub-service like, are you dealing with metrics?
Are you dealing with deployment? I have read or write. those are attributes of the request itself. And then at the macaroon, there’s like a filter on that. you know, and basically all I’m doing is checking to see, like, does the macaroon say this is allowed? Right. And the thing that you’re testing is that you couldn’t get a macaroon that would allow you to, you know, access somebody else’s application or whatever, unless you already had access to that application.
Right. A really neat thing that you can do with macaroons. And I think also with biscuits, which we should talk about in a second, right. is like the notion of confinement for requests, to make that concrete. Like, this is the idea about like, I’ll trust a macaroon. If it’s accompanied by some other context that says this is okay.
Right. And the macaroon paper, their examples for that is I’ll trust this request. If it comes from a specific IP address, which when I’m reading paper is kind of silly, right? Like when am I ever going to use that? like, I’m not going to trust IP addresses to begin with, but in our system we actually do, we can trust the IPV6 addresses that we have because they encode a bunch of information and we have a software defined network that, you know, verifies that you know, you can’t spoof addresses and things like that.
So I can build macaroons that say, if you’re a running instance on our network, you could talk to the API and do these things just by dint of being from that address. I can issue a macaroon with a caveat that says, allow this action. if you’re coming from this specific V6 address and that actually expresses something useful on our system, but you can do other things like I’ll trust this macaroon, if it’s, you know, on an MTLS connection with this certificate or anything else you can think to contextualize a request, you can kind of bake that.
Deirdre: So not to cut you off, but we talked about protobuf tokens. We talked about protobufs. There are protobuf tokens. When are protobuf tokens and how are they different?
So this is what I actually ended up implementing. when I was implementing an OAuth 2 system for Flynn, and it was the simplest thing that would work for me, which was a signed protobuf message. So you define the exact characteristics of the token that you need, perhaps you need it to expire and it needs to have a user ID, group ID, that kind of stuff.
And you put that in a protobuf message and then you have an outer wrapper for that protobuf message that just says two fields that are both bytes fields. There’s, the actual inner message, which is just encoded as bytes. And then there’s a signature field and you could optionally include a key ID in there if you want the ability to rotate, keys easily and everything else is just in the verifier.
So the verifier knows when it either has only one key or it has a key ID, and that has the exact parameters that you’re expecting as far as the algorithm, you could just use ed25519 or similar, and this is the kind of just roll your own token, but in the simplest possible way.
And it ends up being like a few hundred lines of code for both making tokens and verifying tokens.
Deirdre: And also like all of the things that we say should be out of band and not about parsing a header are that way.
Right. You just have to parse this outer message to get the opaqu, blobs that are the signature and the inner message and then potentially the key ID.
Deirdre: Yeah. Yeah.
David: I think that’s the main insight is that your outer protobuf has a bytes field. That is another protobuf, but you don’t decode that until after you’ve checked the signature.
Jonathan: Yeah, exactly.
Deirdre: Good. This is a little bit of the authenticated encryption with associated data. it, it will not verify if the thing that goes around the whole thing does not verify as well. who is using this? Is anyone using this?
Jonathan: I have seen and heard rumors that this is used pretty widely in large services. I think that the answer is like, this is used in places it’s just it doesn’t really have a name outside of the internal names for it. And it’s just something that you reach for when you just want something simple and you have the resources to implement it properly in all the languages that you need within your system.
Deirdre: you are already friendly with protobufs.
David: Yeah. Getting protobuf into your build system is not nice. And like pre-generating the protobuf implementations and look committing them somewhere is also a pain because those inevitably get out of sync.
Jonathan: I mean, I think it just comes down to, yeah. Are you using already using protocols or not? You can do this with any other system. I was using protobufs already. So it made sense to do it this way. You could do message pack or any, you know, even some bastardized JSON would work for this. I think that the key insight with this system is that you’re just picking the exact properties you need.
You just use one algorithm, you bind it to the key and you don’t implement complex stuff that you don’t need. And you don’t use off the shelf libraries that are known to be vulnerable basically, or not vulnerable but have that have in the past, had vulnerabilities.
David: I think that the wrapping, the outer and the inner is also like a key component of it, because that’s what lets you use protobuf, even though it’s any coding is not like well-defined like there’s multiple encodings for any given message.
Jonathan: There’s no single canonical protobuf encoding, correct.
Deirdre: Awesome. And then one more mentioned, which is: what are Biscuits? We’ve got cookies, tokens, macarons, now biscuits.
Jonathan: Biscuits are basically what you get when you say, Hey, I like macaroons, but I want them to be publicly verifiable. And I would like to use Datalog for the caveats.
Deirdre: What’s Datalog?
Jonathan: Datalog is a specific version of Prolog that allows you to reason about data.
Thomas: Okay. I’m sorry, like the, there’s a lot that makes sense about Biscuits. Right. And like the prime mover behind Biscuits is a really sharp person whenever I’m like, but like, I, I hear the variant of Prolog in my tokens. Right. Like make that make sense.
David: You laugh but the whole point of like a caveats is to get out a yes, no, based on series of facts, which is the entire purpose of prolog/ datalog, right? it’s the language that has an intelligence of a two-year-old because all it does is say yes or no to every question, uh, which is exactly what you want.
Deirdre: yeah, I think we vaguely have plans to go in depth on Biscuits. Cause we all want to learn more about biscuits. So we won’t do that right now
Thomas: But Jonathan, you should, you should take second sell us on biscuits.
Jonathan: I think that they make sense in the same scenarios where macaroons make sense in that you have a complex system and unlike macaroons, you don’t want to have either a central service, that holds the secrets or to propagate token secrets out. And you want to have your authorization logic in your tokens. So it allows you to have as close to a stateless system for verifying authorization as possible because the vast majority of our logic is in your tokens.
And then there’s just enough in the verifier to, to check the tokens, basically. And it is by far the most flexible option we’ve discussed. If you have more of a kind of sprawling system where you have multiple services that need to act independently of each other.
Thomas: I guess also, like in fairness, like I said before, when you actually try to implement like a bunch of policy with macaroon caveats, you wind up in kind of, it gets subtle. and the one thing prolog gives you is some clarity about how you’re going to resolve those things, right? Like it’s well specified what, like how you’re going to actually come up with a yes, no answer.
or at least better specified then with kind of arbitrary caveats.
Jonathan: Yeah, I would say that you’re basically putting the complexity upfront. So by far the most dangerous, well, one of the most dangerous part of the Biscuits is the verifier that is handling the datalog. Because if you have a bug in that you can end up with just wide open where a token may verify when it shouldn’t.
Whereas I think that with the simpler implementations of macaroons and certainly the tokens that don’t really have policy in them, that’s not, a potential issue. As soon as you get complicated macaroons, I think that you end up with something similar in complexity, using datalog actually has some nice properties in that a fully mature system that use this could actually tell you why it token isn’t verifying to a very precise degree that I don’t think any other system can.
Thomas: Sure. they’re atenuable too right. You can take them, you can take a biscuit and then make a more restrictive biscuit, but Biscuits are entirely asymmetric cryptography
Jonathan: Yeah, that’s correct. They have the same, that same property that macaroons has where you can add additional constraints to them on the client side.
Thomas: That’s like cryptographically tricky to do. Isn’t it.
Jonathan: Yes. I mean, I think that there, there is a way to do it with classical asymmetric cryptography. The, and you can look at the biscuit repo to see the, the options, the main problem with it is it used a lot of bytes and it’s kind of slow.
David: Alright so to kind of cap things off. I think it would be interesting to kind of zoom through a couple of different scenarios where you’re doing authentication and talk about what are good options for your tokens or at least realistic options for your tokens. so starting with the simplest one, you have like one web server, that’s doing your content and doing your auth and is implemented in some web framework, such as rails.
what do you do there?
Thomas: I would do a 32 byte random number. That’s a key into a
Deirdre: Yup. Yup.
David: Your options are the random key into a database. what about like the things that are built into the web framework? The one on rails, the message. I don’t remember what it’s called the Fernet in Python. those are likely reasonable as well. until you need to build in revocation, at which point you have some more rows in your database again, moving on to that, let’s say you just have two different apps and you want to share log-in between them, but you control everything.
What do we do there?
Thomas: My answer will be different than your answer, but my answer would be, I would share a key, like a symmetric key between those applications and then do a simple signed, you know, I’d probably just use rails message encrypter or Fernet is probably what I would use for— the Python fernet library
David: Well, let’s say that they’re in like different languages.
Thomas: I would implement Fernet’s construction in a different language.
Jonathan: I would either do that or implement just the sign protobuf, construction that I described.
David: I would probably go with a static profile jWT. Is that on the root domain? Assuming they’re sharing a domain.
Jonathan: I think the answer for this is conditional based on whether you have like implementing a static profile JWT, like in theory, you can do that. If you just understand a little bit about security. implementing a fully custom token like I suggested only works if you actually have the resources to safely implement a library that is generating, verifying those tokens and you’re confident in that ability.
Thomas: if you were doing single sign-on and you had to choose between SAML and OIDC with JWT and you didn’t get to do static profile JWT, which would you pick?
Deirdre: Dear god.
Jonathan: that’s just wrong. don’t, don’t that choice
David: like what you do after the SAML, but that’s kind of a poor question because the SAML doing SAML is completely unrelated to the token. Like you can do whatever you want after you do SAML. Correct? you’re getting an assertion from someone in the form of XML, but you’re not using that assertion in your token.
Thomas: I don’t know that I totally agree. Thought that with how you’ve boiled that down. Right. I think that like that to me there, to me, they’re doing similar things like, OIDC and SAML. they’re just using different formats to accomplish it.
David: Well, I’d still be doing a OIDC before SAML.
Jonathan: Yeah, I mean, I just implemented OIDC and you can implement a nice, clean, extremely static profile for, the OIDC, RP. And then on the IDP side, I we’re just not use OIDC.
David: yes. Trust the TLS deployment with an opaque token, I think is a great way to do OIDC-type auth. In fact, I do that at work at the moment. I think if you don’t wanna trust, TLS as much. I wouldn’t be doing the discovery because that’s actually still trusting TLS. I would just be pinning the keys that I expect, or doing some other form of chained, signed JWT, um
Deirdre: although Ryan Sleevi has basically said, please stop doing public key pinning, it’s bad, or cert pinning
David: yeah, but Ryan Sleevi also said that, discovery for OIDC means that you can, if you can get a TLS certificate issued mis-issued for like a minute through BGP and you impersonate the discovery end point. Now I’ve just taken over your IDP, right? so you can get the same properties of SAML in the sense that you have to put the certificates in beforehand, by simply just putting in the JWT keys, public keys that you expect to know IDC, um, and, and doing the verification, but without, but without doing the discussion.
Thomas: is like, this is a Twitter discussion that drove Ryan Sleevi so far around the bend possibly recommended using DNSSEC and DANE to solve this problems.
Deirdre: who wins? no one wins If you reduced to DNSSEC.
David: I think no one wins with auth tokens in general, because the answer is basically as soon as you get past one server, everything sucks.
Deirdre: okay. Does that bring us down to signing with a third party? If we design it from scratch, what we would do?
Thomas: if you get to design it yourself from scratch, you’d use signed protobuf tokens. Right? You do something like that. the problem is never get it. Like when, when these, when these discussions come up, people start talking about like, what do I use instead of JWT with OIDC? And it’s like, that’s not a real discussion.
Right? The, you know, OIDC is JWT,
Deirdre: Like you have to integrate with something somewhere and if you aren’t, you will.
David: I’d be doing constrained OIDC, where from the client’s perspective, I’m just getting a opaque token back that only works for this one thing. And on, on the IDP side, you need to be able to discern between what you’ve issued to who, but then it’s really just a problem on the IDP and, you know, making that the IDPs problem means that this is now just a Google problem and a Facebook problem, or an Auth0 problem. And not like everybody else’s problem.
Thomas: Awesome. So, um, yeah, I think the answer for this whole thing is signed Protobuf tokens. Just use you possibly can. And, uh, Jonathan, thank you so much for introducing them to me. This has been awesome.
Jonathan: Yeah, thanks for having me. This has been fun.
Deirdre: Does it have to be, can it be something, It can be something
Jonathan: can be anything. I mean, think that like the canonical implication that I’ve seen of this, is protobufs, but there’s no reason you couldn’t use like message pack or whatever. Your favorite
Deirdre: Ooh. could Serde I could have a struct in Rust and I could Serde it into my favorite encoding
Thomas: That’s how we did macaroons with message pack
Deirdre: BAM. All right. I’m just going to do this forever. Um, did you open source your thing, Thomas?
Thomas: We’ll never open source right? our thing.
David: Well, B think in the future, we should have Jonathan back to talk more in depth about Biscuits to talk more in depth about how the hell he has authenticated source IP addresses. Um, thanks to Wireguard!
Jonathan: Honestly, you should probably have the author of Biscuits.
Deirdre: We’ve talked to them as well. So we might try and get like a nice panel of, " let’s talk about Biscuits". Um, but yeah. Thank you so much for coming. any final closing thoughts,
Thomas: I’m spent,
Deirdre: Cool. All right. Thank you.