The JSON Web Token (JWT) described in RFC 7519 (https://tools.ietf.org/html/rfc7519) is a standard that is commonly used to represent tokens.
Tokens are, in that case, a long string composed of three dot-separated parts:
- Header: This provides info on the token, such as which hashing algorithm is used
- Payload: This is the actual data
- Signature: This is a signed hash of the token to check that it's legitimate
JWT tokens are base64 encoded so they can be used in query strings.
Here's a JWT token in its encoded form:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJ1c2VyIjoidGFyZWsifQ
.
OeMWz6ahNsf-TKg8LQNdNMnFHNtReb0x3NMs0eY64WA
Each part in the token above is separated by a line break for display purpose. The original token is a single line.
And if we use Python to decode it:
>>> import base64 >>> def decode(data): ... # adding extra = for padding if needed ... pad = len(data) % 4 ... if pad > 0: ... data += '=' * (4 - pad) ... return base64.urlsafe_b64decode(data) ... >>> decode('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9') b'{"alg":"HS256","typ":"JWT"}' >>> decode('eyJ1c2VyIjoidGFyZWsifQ') b'{"user":"tarek"}' >>> decode('OeMWz6ahNsf-TKg8LQNdNMnFHNtReb0x3NMs0eY64WA') b'9xe3x16xcfxa6xa16xc7xfeLxa8<-x03]4xc9xc5x1cxdbQyxbd1xdcxd3,xd1xe6:xe1'
Every part of the JWT token is a JSON mapping except the signature. The header usually contains just the typ and the alg keys. The typ key says it's a JWT token, and the alg key indicates which hashing algorithm is used.
In the following header example, we have HS256, which stands for HMAC-SHA256:
{"typ": "JWT", "alg": "HS256"}
The payload contains whatever you need, and each field is called a JWT Claim in the RFC 7519 jargon.
The RFC has a predefined list of claims that a token may contain, called Registered Claim Names. Here's a subset of them:
- iss: This is the issuer, which is the name of the entity that generated the token. It's typically the fully-qualified hostname, so the client can use it to discover its public keys by requesting /.well-known/jwks.json.
- exp: This is the Expiration Time, which is a timestamp after which the token is invalid
- nbf: This stands for Not Before Time, which is a timestamp before which the token is invalid
- aud: This is the Audience, which is the recipient for whom the token was issued
- iat: This stands for Issued At, which is a timestamp for when the token was issued
In the following payload example, we're providing the custom user_id value along with timestamps that make the token valid 24h after it was issued. Once valid, that token can be used for 24h:
{
"iss": "https://tokendealer.example.com", "aud": "runnerly.io", "iat": 1488796717, "nbt": 1488883117, "exp": 1488969517, "user_id": 1234
}
These headers gives us a lot of flexibility to control how long our tokens will stay valid.
Depending on the nature of the microservice, the token Time-To-Live (TTL) can be very short or infinite. For instance, a microservice that interacts with other microservices within your system should probably rely on tokens that are valid for a while to avoid having to regenerate tokens all the time. On the other hand, if your tokens are distributed in the wild, it's a good idea to make them short lived.
The last part of a JWT token is the signature. It contains a signed hash of the header and the payload. There are several algorithms used to sign and hash. Some are based on a secret key, and some are based on public and private key pair.