tags : OAuth (Open Authorization)
FAQ
History
- First draft in 2012
- Final draft in 2015 : https://datatracker.ietf.org/doc/html/rfc7519
What JWT does differently than Web Sessions?
- Instead of an
opaque token
in a Cookie, we actually embed theuser_id
itself butsigned
. - The
signature
can only be generated by the server which has access to asecret
signature
=secret + payload + header
- When we send the JWT, we send the
signature + payload + header
. This way, if any ofpayload
orheader
is tampered,signature
won’t match. - The usecase is somewhat different too, think
stateless
v/sstateful
- More importantly, Web Sessions are very tightly knit with Cookies, whereas JWTs are not. While it’s a safe practice to store JWT in Cookies, it doesn’t have to be that always, depending on usecase, client can store JWT in memory, session-storage, others etc.
Example of a scene where JWT useful (Need to verify :))
- I made this up, idk if makes sense or is correct
- S:Server,C:Client,R:Resource
S
wants to giveC
access toR
R
does not trustC
.R
trustS
.S
will sign a token(jwt) and send it toC
,C
then use it to accessR
.R
will comply because, it sees that oh, this is approved byS
- Usually the
token(jwt)
is stored in a Cookie and with settings that allows it to be passed toR
. But in certain cases,token(jwt)
might be stored elsewhere and our application logic can make use of it.
S1 and S3 don’t trust each other but both trust S2, but how does S2 trust S1&s3 are legit servers asking for JWT
I am not 100% sure of this answer but guess this is where pre-shared keys/ mTLS comes in
JWKS
JWK vs JWKS
What | Desciption |
---|---|
JSON Web Key (JWK) | A JSON object that represents a cryptographic key. The members of the object represent properties of the key, including its value. |
JSON Web Key Set (JWKS) | A JSON object that represents a set of JWKs. The JSON object MUST have a keys member, which is an array of JWKs. |
What?
- https://datatracker.ietf.org/doc/html/rfc7517
- They keys used for doing JWT stuff
- The values of the JWK Container Object members can change depending on which algorithm is used.
- Eg. JWK container using RSA algorithm and has the following members:
alg, mod, exp, kid
. Some other agl will have other members etc.
How to obtain?
- Typically the JWKS can be retrieved by querying an “endpoint” exposed by the Authorization Server known as a
jwks endpoint
- Eg.
Auth0
exposes a JWKS endpoint foreach tenant
, which is found athttps://{yourDomain}/.well-known/jwks.json
(i.e a private key each tenant)
- Eg.
- There are ways to mock the endpoint: https://github.com/murar8/local-jwks-server
- What about generate?????
Signed or Encrypted?
-
JWT can be:
- signed (JWS - RFC7515)
- encrypted (JWE - RFC7516)
- signed then encrypted (the whole JWS is the payload of the JWE)
- encrypted then signed (the whole JWE is the payload of the JWS)
Verification
Signature verification
- Just make sure you have the correct signature
TODO Expire of the token
What
- JWT is a format of a token.
- Signed but non-opaque, Web Sessions are opaque tokens
- Defines a container to transport data between interested parties.
- JWT is independent of OAuth (Open Authorization) and OIDC (OpenID Connect)
Algorithms for JWT
Process
- First you generate the
.pem
file. Either symmetric/asymmetric - Then you use a pem to jwk/jwks converter thingy
- Then your application uses jwk to create the token
- Later other application can verify if it’s the correct token by using the symmetric/asymmetric key.
Types
Both of these types work in jwt.io, but confusingly it also asks for private key in the ui
But as mentioned, it’d work even if you just give the public key for verification. (which is the case for asymmetric keys)
Also, you can use the content of jwks.json file X.509/PKCS/PKIX private key .pem files to supply the public/private keys, but just giving the jwks.json is much simpler is what I prefer.
Symmetric
- HMAC based
Asymmetric Algorithms
- generate using the private key
- verify using the public key
- Eg. RSA and ECDSA signatures
- When generating the
jwks
for this, you’ll get- Public and Private Keypair Set
- Public Key
- Private Key
- All of them will be json,
Public Key
will have most ofPrivate Key
with some fields missing, eg with es256d
will be miising. i.ed
is a private component.
Concerns
Lot of blogposts on the internet bashing JWT, this is mostly about how often JWT gets misused and not flaw of JWTs itself. The following is just summary from the famous owasp cheetsheet.
Logging out
- This was what was mention in using JWT for stateful stuff. (Not recommended)
- If you really want to do it, here’s an idea from someone: “My favourite solution to this is keep a global list of JWTs that have been revoked before they expired (and remove the tokens after expiry). Instead of letting webservers hit a server to get this list, push the list to each server using a pub/sub mechanism.”
None hashing
- Some JWT libs consider tokens signed with
none
as valid. (BAD) - Sol
- Just use a proper JWT lib
- VAlidate the algorithm is what we expected it to be server side per req.
Token Sidejacking
Token got stolen, impersonation.
The idea is to basically add an user context
(Basically something that the only original user can have). i.e Even if they’re able to steal the JWT token somehow, they won’t be able to steal the user context
token from the hardened cookie.
tbh, this seems like reimplementation of Web Sessions to me, We cannot revoke stuff like in sessions
but with this we can sorta validate but this becomes more prominent when you think that JWT’s are not always meant to be stored in Cookies, in that sense a hardened user context
cookie can provide protection against XSS and hence prevent stealing as described below.
- We can use IP address for the
user-context
, but that’s not a great idea because it can change - Turns out,
a random string+strict cookie
is good enough. Let’s called it theSecure Fingerprint (Secure-Fpg)
cookie. ThisSecure-Fpg
is ouruser context
Client side
- Generate a random string(SHA256), put the raw value of this string into a Hardened Cookie
- Additionally, for the hardened cookie set
Expires
=None
, so that cookie is cleared when the browser is closed.Max-Age
<= value of JWT token expiry (never more)
- This becomes out
Secure-Fpg
. i.euser context
=Secure-Fpg
=raw random string+cookie
- Additionally, for the hardened cookie set
- In the actual JWT token, add a
hash
of theraw random string
. We can send the JWT token as a Cookie or however we desire.
Server side
- On the server side, we keep track of
Secure-Fpg
that we send. (Similar to Web Sessions) - On validation, we check the
user context
cookie against saveduser contexts
- Then we again calculate the hash for the
raw random string
- Then we verify the hash against the hash in the JWT token.
Token Information Disclosure
- JWT token data is base64 encoded but not encrypted
- We can use symmetric encryption if we want to here
Weak Token Secret
- If using weak secret for HMAC
- Attacker can take the JWT and then run an offline attack on it
- This will allow them to resign tokens
Usecases
Stateful application
- See Cookies and Web Authentication
- Use of JWTs for
stateful session management
is 99% of the time BAD, because JWT are designed to be stateless. - JWT is used by an application to allow a client to present a token representing the user’s “identity card” to the server and allow the server to verify the validity and integrity of the token in a secure way. (All this happens in a stateless way)
- Individual stateless JWT tokens cannot be invalidated.
- If you need (logout/access revocation etc), stateless would not work, you’ll need server side state. Just deleting the secure http-only cookie will just delete the token but not really invalidate it.
- You can use client side logic to enforce this or maybe change the jwt secret on the server!
- At this point you might as well use traditional stateful opaque sessions
Stateless application
- Short term authorization tokens
- Great for short term authentication between decentralized systems. Eg. 5 minute expiration between a web api and a websocket service.
- JWTs are good for API tokens
- Web Sessions on frontend, JWT on backend for service to service communication.
- JWT, when implemented well in stateless application can be a good candidate
- Handy in a distributed system or inside a trusted environment also. User-actions may cause requests to several http-endpoints(Microservices) that all have to somehow individually verify the authentication. In this case JWT can help not needed all these to have access to the Web Sessions data store, this become simple as the token will be signed by a trusted entity that the different services trust and they just need to have it’s public key(See PKI).
- See Ways to do it section
- Another example of stateless session using encrypted cookies: vvo/iron-session
Ways to do it
Auth
Use of JWT for Auth means using JWT for stateful stuff mostly which i am not super convinced of
Send it via Cookies
- Cookie Hardening
- Backend w proper CORS policy
Send it via HTTP Bearer token with TLS
- This is what applications which are not Browsers do afaik
- Can be vulnerable to XSS
Info exchange/delegation of access
Sent it in API response and let client decide
- Since the token is signed, we can just send it.
- The client can decide how they want to use it, this is more useful in the usecase of “Information Exchange” compared to Authentication.
Use on OIDC (OpenID Connect)
- OIDC does not mandate the use of JWT as the
ID token
(JAR) /access token
- In fact there’s no structure defined for the token, but using JWT has benefits.
- But OIDC tokens are transparent unlike OAuth(opaque tokens), So JWT fits!
- Allows other flows (hybrid or implicit) to be used.
- Good library support
- Can hold payload
- Signed token, so the RP can still trust it even though it’s been received via an untrusted channel.