wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Generating JWT tokens for tests


There are many options for Authentication and Authorisation. I'm fond of Json Web Tokens (JWT), implementing RFC7519. Mostly because they are like LTPA for grownups, but standard compliant

Quis custodiet ipsos custodes?

JWT contains information that is digitally signed (and optional encrypted), so a receiving end can verify that the information is correct. The key elements here are:

  • the JWT contains a claim, at least the subject that is tamper resistant by being digitally signed
  • JWT issuer and JWT consumer trust each other, by either having a shared secret (bad idea) or using a public/private key pair. The issuer signs the information with a private key. The consumer (your application server) verifies the signature using the public key

So besides protecting the private key of the issuer, you also want to be clear who's keys you trust. The one who holds your identity can impersonate you at any time (so you might rethink if "Login with Facebook" is such a brilliant idea after all).

However when testing systems, you develop local, you want to be able to have any user at your disposal, so you can generate the claim that is the Open Sesame to your test regime

Building a claim

We start by building the raw claim template.json file:

{
  "iss": "Alibaba Caves",
  "aud": "40Thiefs",
  "expSeconds": 300
}

It contains an issuer, an audience and the duration in seconds. The later one is for my convenience. The receiving system might or might not check issuer (iss) and/or audience (aud).

Next step is to create a public/private key pair

OpenSSL does the job quite nicely. Just make sure you don't share the private key!

ssh-keygen -t rsa -b 4096 -m PEM -f private.key
openssl rsa -in private.key -pubout -outform PEM -out public.pem

the public.pem file you need to import into your application server (e.g. Vert.x), but that's a story for another time.

Since I do a lot of testing using curl and Postman, I decided, my little imposter should server its payload on localhost:6660. A few lines of JavaScript do the trick:

const express = require("express");
const app = express();
const port = 6660;
const template = require("./template.json");
const jwt = require("jsonwebtoken");
const fs = require("fs");
const privateKey = fs.readFileSync("./private.key");

const signOptions = {
  algorithm: "RS256",
  expiresIn: `${template.expSeconds}s`,
  mutatePayload: true
};

const renderInstruction = (req, res) => {
  res.send("You need to post a user name, claim details are local here");
};

const renderJwt = (req, res) => {
  const claim = { sub: req.body.toString(), ...template };
  const bearer = jwt.sign(claim, privateKey, signOptions);
  res.json({ ...claim, bearer: bearer });
};

app.use(express.raw({ type: "text/plain" }));
app.get("/", renderInstruction);
app.post("/", renderJwt);

app.listen(port, () => console.log(`Ready when you are on port ${port}!`));

Now you can post to the server: curl -d "John Doe" -H "Content-Tpe: text/plain" -X POST http://localhost:6660 and get JSON back that contains a bearer element.

As usual: YMMV


Posted by on 01 February 2020 | Comments (0) | categories: JavaScript WebDevelopment

Comments

  1. No comments yet, be the first to comment