Authenticate like Google
Overview
This tutorial, at https://wilsonmar.github.io/awt-jwt, examines how the JWT (JSON Web Token) authentication scheme works, in a hands-on, step-by-step approach, with PROTIPs and NOTEs along the way.
BTW, JWT (jwt.io) is sometimes pronounced as “jot”. Others insist on saying J-W-T.
This page had begun below by showing manual use of a demo UI consuming service (Google’s URL Shortener service because Google was an early adopter of JWT for all their APIs).
However, Google discontinued support of their URL Shortener service in 2018. But I haven’t had time to change this page.
Paul McLean at testdataservices.com.au enables the data and diagnostics to properly test OIDC JWT. His service enable identification of issues that cannot be done just connecting with production services using JWT.
We examine the exchange of data between client and server as illustrated on my diagram of what happens behind the scenes to generate JWT tokens.
The technical specification for JWT was defined May 2015 by Internet Engineering Task Force (IETF) as RFC 7519 ( formatted and PDF).
NOTE: JWT is Updated by JWS (JSON Web Signatures) https://www.rfc-editor.org/info/rfc7797 that does not use Base64.
It emerged because the XML handling required by
SAML (Security Asertion Markup Language) became too much for mobile devices.
JWT provides asymetric signing missing in the
Simple Web Token standard created by Microsoft, Google, and Yahoo.
Demo UI consuming service
http://jwt.io generates JWT plus decodes and verifies JWT generated by others.
As an introduction to how Google’s URL Shortener service works, let’s look at the human user interface which web services replace.
-
Invoke a Google Chrome browser. If you do not have one installed, install it from http://google.com/chrome
-
Open an internet browser window to Google’s URL Shortening service for individual Google users:
-
Login using my Google account credentials. URLs shortened previous under your account should show up on the page:
-
Type or paste a URL in the text box and click the blue Shorten URL button.
Google takes the long URL pasted in the form and creates a SHORT URL from it.
-
Use your mouse to highlight a goo.gl SHORT URL value to your Windows clipboard.
-
Alt-click on a SHORT URL (in blue) to copy the URL link.
You are taken to the URL.
This page at Google notes that “A unique short URL is created each time a long URL is shortened.” But if you were signed out, the same short URL is reused each time a long URL is shortened by you or someone else.
What happened behind the scenes is illustrated at the lower-left corner of the diagram below.
Diagram
Looking at the bottom left of the diagram (shown in red), we obtain a shortened URL in a JSON response to submitting a long URL to shorten.
The previous section describes this action on the goo.gl website. But we are examining this so we can do it on our own client instead.
Either way, JavaScript in the client makes a call to the API end-point within the Google Cloud Platform:
https://www.googleapis.com/urlshortener/v1/url
The client makes the call after placing the URL to shorten in the body of the call along with a AccessToken that the client obtained from another end-point:
https://accounts.google.com/o/oauth2/token
The call to that was made by providing a JWT Assertion string obtained from a call to a utility JWT library running on the client, providing credentials obtained from Google based on the Google account which signed in (represented at the upper left).
The gray area on the right side describes the internal processing typically done by the utility JWT library loaded on the client. Other established libraries (such as OpenSSL) are called to perform the complex math needed to sign signatures required by JWT. This tutorial will later dive into the internal workings of these libraries.
But first we need to look into obtaining inputs to those libraries from the Google Cloud Platform Console.
The client making the call needs to have just four pieces of information needed to make the call:
-
The password “notasecret” (not a secret). Why this still needs to be provided is a mystery to me because it is always the same because secrecy now depends on cryptography provided by the next two items:
-
The service email for a specific API project looks like an email:
123456789012@developer.gserviceaccount.com
-
The .p12 file fingerprint.
-
How long the program allows access tokens to live. The Google API allows access tokens to live up to an hour. Each organization may use a shorter time frame.
Next, let’s look at this process.
Get .p12 from Google API Console
This is done to provide an example for the day when you’ll use your own API management platform instead of this example.
-
Use an internet browser to go to the Google Developers Console at https://console.developers.google.com/
-
Sign-in with a company account or your own personal account.
PROTIP: For testing production applications and their APIs, testers normally obtain credentials from Security or DevOps personnel who create separate company Google accounts which they then specify for Google to create Service accounts.
The most popular APIs (among all Google users) is presented:
Click Enabled APIs if you already have keys.
Otherwise: -
First time visitors are asked to create a new project. Click on Create Project….
-
Google suggests a Project ID.
PROTIP: Specify a version number after each project name.
-
Create a project from the Project Dashboard.
-
Type “shorten” in the gray search field.
-
Select “URL Shortener API” when it appears.
PROTIP: Create a bookmark to this Developers Console for your sample URL Shortener API project.
Enabled APIs
-
Click on “Credentials” on the left menu.
A .p12 (private key) file named with the new fingerprint created is automatically downloaded.
BTW, “.p12” is a contraction of the file’s internal format being PKCS #12 among Public Key Cryptography Standards defined by RSA Laboratories at https://www.rsa.com/rsalabs/node.asp?id=2138. As explained in http://en.wikipedia.org/wiki/PKCS12, “.p12” is the “Personal Information Exchange Syntax Standard”.
The private key password “notasecret” created by Google when the .p12 file was generated does not change because it is not used since the whole JWT mechanism is designed to avoid sending passwords across the internet.
Since the long name of the public key fingerprint file necessarily changes for each installation, whatever file used is renamed to something like “484313????01.urlshortner.private.p12” before being copied to the script folder.
PROTIP: If you are doing this within an enterprise, corporate security people will have likely defined naming conventions, procedures for safe storage, and policies for usage of key files. An example of safe computing is to burn the .p12 and other such files onto a DVD disk media kept in a fire-proof safe operated by Edward Snowden and one other person.
A DVD is used because data on magnetic and solid-state hard drives can degrade over time. Most secure organizations now have policies against use of USB drives. Physical possession of the private keys can be a complex discussion since the keys need to exist on computers.
Signing
Signing involves applying a known mathematical formula to a string such that it yields a set of numbers.
Because the algorithm is rather complex, programs doing the signing usually make use of a library that contains functions to do the calculation.
Making API calls using JWT requires the acquisition of a temporary access token which is valid for a short period of time. Google allows the amount of time to be determined by the caller, as long as it’s less than an hour.
An access token (within parameter named “pAccessToken”) obtained from Google is added into the HTML header of the request. “Bearer” refers to the Bearer Token Usage standard http://tools.ietf.org/html/rfc6750 which Google uses so cryptographic keys do not need to be sent over the network.
Google wanted to use a more secure mechanism than users sending a password over an internet which can be snooped.
This means that applications and test scripts emulating applications need the logic to repeat access token requests when needed.
Sample 1
-
https://github.com/kumartarun/JWT-with-Node-JS using jwt-simple/Crypto to create JWT token server side and passport.js to get into Twitter, Facebook, etc.
UserSchema.statics.encode = function(data) { return JWT.encode(data, CONSTANT.TOKEN_SECRET, 'HS256'); }; UserSchema.statics.decode = function(data) { return JWT.decode(data, CONSTANT.TOKEN_SECRET); };
Sample 2
https://github.com/auth0/node-jsonwebtoken/ lists several algorthms to generate digital signatures (HMAC using SHA-256 hash algorithm, etc.). But the one used on the client needs to match what the server uses.
Node implementation
Sample code using that Node library is:
// sign with default (HMAC SHA256) var jwt = require('jsonwebtoken'); var token = jwt.sign({ foo: 'bar' }, 'shhhhh'); //backdate a jwt 30 seconds var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh'); // sign with RSA SHA256 var cert = fs.readFileSync('private.key'); // get private key var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'}); // sign asynchronously jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256' }, function(err, token) { console.log(token); });
Other implementations:
- https://www.youtube.com/watch?v=vziqErg6NZs https://vimeo.com/129702273 Martin Gontovnikas (@mgonto, Dev Advocate from Argentina at Auth0) http://mgonto.github.io/apis-strike-back/