Background
JSON Web Token (JWT) is an open standard ( RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
What this essentially means is that JWT helps you secure your application by allowing to securely share claims such as user data between your application and the client that is communicating it. In this post, I will explain fundamentals of JWT and how it works.
When you would use JWT?
As mentioned before JWT can be used to secure communication between two parties that exchange data. Following are some common use cases -
- Authorization: This is a very common use case of JWT. When users log into an application, they are presented with a JWT token. Each of the subsequent requests that user makes to this application must include this JWT token. Your application would validate each of the requests to see if it has valid JWT before processing it.
- Information exchange: You can also transfer information in JWT in a secure manner. This means JWT can have data as part of it. Note that this information sent is visible to anyone having access to that token. However, no one can alter this information since the token signature is calculated based on the information it holds and altering any data will change the signature which would invalidate the token. We will see this in detail in some time.
What does JWT look like?
Now that we know when can we use a JWT, let's see how does it look like and what does it comprise of.
A JWT typically looks like -
- xxxxx.yyyyy.zzzzz
- Header
- Payload
- Signature
Let's see what each of these sections represent.
Header: Header is a JSON that mainly consists of two parts - the type of token which is JWT and the algorithm used for hashing. For example,
{ "alg": "HS256", "typ": "JWT" }
The header section of JWT is Base64 URL encode of above JSON.
Payload: This is the 2nd part of the JWT. This section contains the claims or the information that needs to be shared. This is again in JSON format. These claims can be of 3 types -
- Registered claims: These are predefined claims which are optional but useful to convey proper information. Example can be iss(issuer), exp(expiration time), sub(subject) etc. You can see all the claims here.
- Public claims: These can be defined by anyone using JWT but should be defined in IANA JSON Web Token Registry to avoid a collision.
- Private claims: These are custom claims that can be added to share information between two parties as long as both agree on using them. These are neither registered or private claims.
Example -
{ "sub": "Welcome to my blog!", "name": "Aniket Thakur", "iss": "opensourceforgeeks.blogspot.com", "exp": 1530436998 }
Signature: This is the 3rd and last part of JWT. This represents the signature of the token. This is created as follows -
Signature = Hash (base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
As you can see signature comprises of the header and well as payload. So if anyone changes header or payload then the signature would not match and hence JWT validation would fail. This is exactly why I mentioned before that JWT is secure from tampering. Also, notice that a secret key is used to compute the hash value. This secret will never be available to anyone (just the application generating the JWT to protect its resources). And finally, the hashing method would depend on the algorithm you are using. In above example we used - HS256 (HMAC with SHA-256).
So, assuming the secret key used is "secret", for the example we have used above JWT would look like -
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJXZWxjb21lIHRvIG15IGJsb2chIiwibmFtZSI6IkFuaWtldCBUaGFrdXIiLCJpc3MiOiJvcGVuc291cmNlZm9yZ2Vla3MuYmxvZ3Nwb3QuY29tIiwiZXhwIjoxNTMwNDM2OTk4fQ.8pmcCeFS9gx8Yb-DPRkAihhW7mUxAZkklYHHme5a0tU
where
header : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 payload : eyJzdWIiOiJXZWxjb21lIHRvIG15IGJsb2chIiwibmFtZSI6IkFuaWtldCBUaGFrdXIiLCJpc3MiOiJvcGVuc291cmNlZm9yZ2Vla3MuYmxvZ3Nwb3QuY29tIiwiZXhwIjoxNTMwNDM2OTk4fQ Signature : 8pmcCeFS9gx8Yb-DPRkAihhW7mUxAZkklYHHme5a0tU
You can also see this JWT in action - https://jwt.io/.
NOTE2: Also you must have realized by now that header and payload are just base64 URL encoded values and that anyone with access to token can decode and read these. So you must never add any sensitive information to these sections. JWT just ensures that the data cannot tamper but the data is visible to everyone with the access to the token.
How does JWT work?
Now that we saw fundamentals of JWT let's see how JWT is actually used to protect resources in an application.For simplicity let's assume we have our own server application which has an authentication module and a set of APIs that must be protected. First user or the client would authenticate itself against the server. The server will send the JWT in the response of successful authentication call. This token will be used by the client in all subsequent API calls made to the server. You can send this token in the headers of the API call. Now in each API call server will check if the JWT is valid and process the request based on the validity of the token.
We already saw how JWT tokens are created. Now let's see how they are verified. Once the server receives JWT token it will extract payload and header section. Then it will use these parts along with the secret that is stored only on the server to calculate the signature. If the signature calculated is same as the one that is received from the JWT then the JWT is valid and the further processing can happen. If the signature does not match then it means someone has tampered with the request and it must not be allowed to execute. You can send a 401 - unauthenticated response in such cases.
Ideally, you would have a separate API server and a separate authentication server in which case you can keep the secret is a centralize place like a database and read it from both the servers to generate signatures of JWT.
Flow is something like below -
Summary
- JWT can be used to securely share claims between two parties. This can either be used for protecting your resources on the server or sharing data securely.
- JWT protect the data from being tampered but it does not prevent anyone from viewing that data (Since the data is just base64 encoded string). So never send sensitive data as part of JWT.
- Always add an expiry to the JWT. So if your token is compromized for some reason it would not be valid post its expiry. The client can reach out to the server for the new token in this case.
- Always use https for sending JWT since it prevents unauthorized users from stealing the JWT.
- You can use https://jwt.io/ to generate and see JWT yourself.
No comments:
Post a Comment