JSON Web Tokens (JWTs) are signed tokens issued by a server that it can use to verify a claim made by a client. This blog post is the first in a series where I implement authentication based on JWT in a Spring Web application with an Angular JS front end.
These are the blog posts in this series:
- Part 1 - Discussion of JWT and implementation
- Part 2 - A Spring User Profiles API
- Part 3 - Issuing a token from the server
- Part 4 - Verifying the token sent back by the client
- Part 5 - Securing the front end
What is JWT?
The official JWT website defines JWT as:
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
A JWT
contains 3 parts - a header
, a payload
and a signature
. A JWT
can in turn be represented as a JWS
or JWE
. JWS
stands for JSON Web Signature as defined in RFC 7515 and JWE
stands for JSON Web Encryption defined by RFC 7516. In a JWS
, the payload being sent is not encrypted, whereas it is encrypted in a JWE
1. This blog post will deal only with JWS
.
Structure of a JWT
A JWT has the following structure:
base64(header) + "." + base64(payload) + "." + signature(header, payload, key)
The signature itself is generated by signing the header and payload with a key, for example using the HMAC-SHA256 algorithm:
HMASHA256(base64(header) + "." + base64(payload), key)
A JWT header is a JSON object that typically has the following values:
alg
- The algorithm used for signing the token.typ
- This optional parameter, set toJWT
declares this JSON object as a JWT.
An example JWT header when the algorithm used is HMA-SHA256:
{
"alg": "HM256",
"typ": "JWT"
}
A JWT payload contains a series of claims. There is an IANA “JSON Web Token Claims” registry that has a number of claim names reserved for specific purposes. Applications are free to use any other names, except these for their claims. Claim names that are important include exp
that represents the expiration time on or after which the JWT MUST NOT be accepted for processing. The following payload sets issuer, expiry date and a username.
{
"exp": 1467509846,
"iss": "in.sdqali.jwt",
"username": "greenrabbit948"
}
Generating a JWT
For the header and payload shown above, if we were to generate a JWT with the HMAC256 algorithm and key secretKey
, it will look like this:
* Header - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
* Payload - eyJleHAiOjE0Njc1MDk4NDYsImlzcyI6ImluLnNkcWFsaS5qd3QiLCJ1c2VybmFtZSI6ImdyZWVucmFiYml0OTQ4In0
* Signature - rStkUmx0SRWjBxKFVF2-lwwZNxlkGRJ4uH49TCIIN7o
The end token will have the following form:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Njc1MDk4NDYsImlzcyI6ImluLnNkcWFsaS5qd3QiLCJ1c2VybmFtZSI6ImdyZWVucmFiYml0OTQ4In0.rStkUmx0SRWjBxKFVF2-lwwZNxlkGRJ4uH49TCIIN7o
I have been implementing the JWT RFC to learn about it and it was fairly straight forward. I did the token generation part and did not finish the token verification part. The code for that exercise can be found here. A more complete implementation of the RFC for the JVM is jjwt and the rest of the series will be using that implementation. The JWT website has a debugger that allows for creation and verification of tokens.