JWT |jät| JSON Web Tokens - 401-advanced-javascript-aimurphy/seattle-javascript-401n13 GitHub Wiki

JWT will format the information into a json object (), which can be either signed, encrypted or both.

To sign a token you'll do this digitally either using a secret (via HMAC algorithm) or a key pair (using RSA or ECDSA).

If a token is signed, but not encrypted, everyone can read the contents of the token. If it is encrypted it can provide secrecy between parties.

Use Cases

Authorization, this is the most common use. Once a user is logged in and receives a token, it is included in all subsequent requests and gives that user access to any routes, services, and resources permitted by that token.

Info Exchange, JWTs are a great way to securely pass data between parties because the signatures is a protective measure to ensure the senders are who they say they are and that the content hasn't been tampered with, since the signature is calculated by the header and payload.

Token Structure:

In its compact form, every jwt is made of 3 parts separated by dots:

header.payload.signature

Each of these parts is a base64Url string.

Header

contains the token type, jwt, and the signing algorithm, which can be HMAC SHA256 or RSA, and it might look something like this before it gets encoded to be pt 1 of the token:

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

holds the claims. Claims are the info about the entity or user, and they come in 3 flavors:

REGISTERED - predefined and recommended but not mandatory (ex: jti, iss, exp, sub, aud...see them all). Notice they're only 3 char long. This is because jwt is compact!

PUBLIC - try to define these with IANA JWT registry or as a URI with a collision resistant namespace. You can name it freely but you might run into collisions if you're not careful.

PRIVATE - none of the above, these are made up and shared between parties who've agreed on using them.

sample payload before it gets encoded into pt2 of the token:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature

signature is used to verify that the message hasn't been tampered with in transit, and it can't happen unless you've got the following ingredients: encoded header, encoded payload, a secret, and the signing algorithm specified in the header.

If you use a private key, it can also be used to authenticate the sender of the jwt. Whoa!

So how does this really work?

When a user logs in successfully a token is sent.

The user will use this token to then access any protected routes or resources from the server, typically in the authorization header using the bearer schema, like this: Authorization: Bearer <token>.

The server's protected routes will check for a valid token in the Authorization header, and if it's there: access granted!


👾app(client) --req auth to auth server--> 🛡auth0(auth server)
👾app(client) <--if auth granted, sends 💰token-- 🛡auth0(auth server)
👾app(client) --uses token💰 to access routes/resources--> 🗃your API(resource server)

Token Wisdom

  • Keep it secret. Keep it safe. Take care of your signing key, sharing is on need-to-know basis only.

  • Keep it simple, it's a token, not a lock. Tokens are easily decoded (remember when we pasted it into the website?) so don't put anything important in the payload, keep it simple. Signing only protects against tampering it doesn't hide anything.

  • Keep them fresh. Once signed, a token is valid FOREVER--unless the signing key changes or you pre-set an expiration. If you do either of those, you'd better have a strategy in mind and be keeping track.

  • Keep using HTTP. Don't send tokens over non-HTTPS connections as those requests can be intercepted and tokens compromised. 🤨

  • Keep in mind your use cases. Adding a secondary token verification system that ensures tokens were generated from your server, for example, may not be common practice, but may be necessary to meet your requirements.

sources:

auth0/node-jsonwebtoken on github

JWT.IO

⚠️ **GitHub.com Fallback** ⚠️