An
authentication server provides a client with a
JSON Web Token, and the
authentication server will also handle requests from application servers to verify tokens supplied by clients.
Algorithm
Generally, the token generation code follows this process:
- 1. Initialise the token header as a set of JSON objects.
- 2. Initialise the token payload as a set of JSON objects.
- 3. Base64-encode the header and payload independently. This gives us the unsigned token.
- 4. Using the HMAC SHA256 algorithm, and a secret key value, generate the signature for the unsigned payload.
A token, therefore, will have three segments: a) header, b) payload, and c) signature. The first two are Base64-encoded JSON objects, and the third is the encoded signature of the first two segments. This can be seen in action when generating a token with the debugger at jwt.io:
https://jwt.io/#debugger-io?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpX
VCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxN
TE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
When decoded, the token would look something like this:
{ "alg": "HS256", "typ": "JWT" }
{ "sub": "Web Application", "name": "Michael", "iat": 45435334 }
{ SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c }
JavaScript Implementation
Several JavaScript libraries are needed for the implementation here. The crypto ones are referenced on
Joe Kampschmidt's blog:
- jquery-3.3.1.min.js
- jquery.base64.min.js
- crypto-js.min.js
- hmac-sha256.min.js
- enc-base64.min.js
To initialise the header and payload as JSON objects,
JSON.parse() is used.
var headerjson = '{ "alg": "HS256", "typ": "JWT" }',
headerobj = JSON.parse(headerjson);
var payloadjson = '{ "sub": "x555", "name": "Michael", "iat": 445644543534, "issued": ' + Math.floor(Date.now() / 1000) + ' }',
payloadobj = JSON.parse(payloadjson);
Next, independently
encode the header and the payload:
headerb64 = btoa(unescape(encodeURIComponent(headerjson)));
headerb64str = decodeURIComponent(escape(window.atob(headerb64)));
payloadb64 = btoa(unescape(encodeURIComponent(payloadjson)));
payloadb64str = decodeURIComponent(escape(window.atob(payloadb64)));
The unsigned token will consist of two segments, one for the encoded header and the other the encoded payload:
var unsignedToken = headerb64 + "." + payloadb64;
Finally, the crypto libraries provide the HMAC SHA256 algorithm used here for signing the token:
var secretKey = "Password1";
var tokenSignature = CryptoJS.HmacSHA256(unsignedToken, secretKey);
var encodedTokenSignature = CryptoJS.enc.Base64.stringify(tokenSignature);
gentoken.value = encodedTokenSignature;
And finaly, I've put all three segments together to form the signed token:
allsegments.value = headerb64 + "." + payloadb64 + "." + encodedTokenSignature;