JWKs & JWTs & JOSE
Topic
Ok so I hear a lot about JWK tokens but I don’t fully understand what they are or how they work. But they are essential for most authentication use cases in the app.
Conjecture
Ok I think that a JWK is the hash of an object or set of data. The JWK is encrypted using a private key and a public key. The private key of the corresponding public key can then be used by a key authority to verify that the JWK was generated using the proper keys and then it can also check the data that was encrypted to see if the token was valid. At least thats what I think. The details are a little hazy.
Research
Ok so I was muddying two interrelated concepts:
- JWT (JSON Web Token) - So a JSON web token is a compact URL-safe way of representing claims between two parties. Claims referring two the fact the a requester is “claiming” that they have access to certain resources. URL-safe meaning that it could be passed in a URL to a server without any need to change the characters or definition of anything. A JWT is signed using keys that can be expressed in JWK format.
- JWK (JSON Web Key) - A JWK is a JSON data structure that represents a cryptographic key. It is mostly used to share public keys in a standard format.
In my conjecture I was mostly describing a JWT token which would be signed using a private key. The corresponding public key would then be published publicly and used to verify that the JWT had be signed using the corresponding private key. When a JWK is rotated it means that the public and private keys for the auth system are updated so all previously generated JWTs are no longer valid. A new token then needs to be generated for the user using the new private key so that the new public key can be used to verify that the JWT is valid.
At the end of the day though: JWK and JWT both just refer to standard formats by which tokens and keys can be represented. Also remember Tokens are used by users to represent the data/permissions that they have access to or put another way: their “claims”. Keys are used to verify that the Token that a user has was issued by the proper authority.
Here is the official spec for JWKs: https://www.rfc-editor.org/rfc/rfc7517
Here is the official spec for JWTs: https://www.rfc-editor.org/rfc/rfc7519
Reading through the spec I realized there is another important concept to note: JOSE header the JOSE header is used to define the format and encryption method used in a JWT. Here is an example of a JOSE header:
{"typ":"JWT",
"alg":"HS256"}What this means is that the following information is a JWT, signed as a JWS using HMAC with SHA-256.
Which is worth pausing on, because it doesn’t actually match the public/private key story I told above. HS256 is HMAC, and HMAC is symmetric — one shared secret both signs and verifies, and there is no public key to publish. The asymmetric case I was describing is RS256 or ES256, and that is where JWKs earn their keep: you publish the public half at a JWKS endpoint so that anyone can verify a token without being able to mint one.
A JWT essentially then has 3 parts, joined by dots:
- JOSE header
- Claims set — this is the payload
- Signature
I had this wrong on the first pass: I listed the payload as a third thing sitting alongside the header and the claims, but the claims set is the payload. The third part is the signature. Each of the first two gets converted to UTF-8 octets, Base64url-encoded, and joined with a . — then the signature is computed over that joined string and appended.
One more thing I was sloppy about above: a standard JWT is signed, not encrypted. Base64url is an encoding, not a cipher, so anyone holding the token can decode the claims and read them in plain text. The signature proves the token hasn’t been tampered with and came from the issuer; it hides nothing. If you actually need the contents secret there is a separate standard for that, JWE.
Final Summary
Essentially, JWTs are tokens, JWKs are a JSON format for representing keys — usually the public half, published so other people can verify your JWTs — and both are really just standards for representing keys and tokens so they can be safely passed around in URLs and headers. JOSE is the umbrella family those standards live in (JWS for signing, JWE for encryption, JWK for keys, JWA for the algorithms), and the JOSE header is what tells you which of them a given token is using.
The two things I’d flag for my past self: the third part of a JWT is the signature, not the payload, and signing is not encryption.