FAQs »

How can I create and sign a JWT in my script?

The JSON Web Token (JWT) concept has become sort of a de facto standard for web applications.

It was intended to solve the need for passing authentication information and permissions claims between related applications, in a way that is URL-friendly and cryptographically signed so that the receiving application can verify it wasn’t forged.

Sections of a JWT

A JSON Web Token in its final form is built from three sections: a header, a payload, and a signature.

The JWT Header

The header identifies the token as a JWT and tells what cryptographic algorithm was used to sign it. This same algorithm can be used by the receiver to verify it, if the receiver also has the corresponding key.

A typical example of a JWT header is:

{ "alg": "HS256", "typ": "JWT" }

The JWT Payload

The payload is a free-form JSON object that can include pretty much anything you want. Usually, the payload identifies the user that the JWT represents. It can also convey other user information or “claims” about what the user should be allowed to do.

Here is a simple example of a payload including a user ID of the “subject”, the subject’s name, and an epoch timestamp of when the JWT was issued.

{ "sub": "12345", "name": "Dude McBob", "iat": 1679354437 }

You can add other fields to the payload as needed.

The JWT Signature

The signature is cryptographically generated from the header and payload, using a cryptographic key.

The purpose of the signature is so that the receiver can verify that the token really did come from a trusted system via a shared key or key pair.

There are quite a few cryptographic algorithms to choose from, and they can be symmetric (like HS256) or asymmetric (like RS256). As long as the receiver has the appropriate symmetric or public-private key, it can use the signature to verify the JWT.

Keep in mind that even though encryption is involved, it is only a signature, and it doesn’t actually protect the contents of the JWT from other parties.

Encoding JWT Sections

A JSON object is hard to stuff into a URL, so the JWT specification requires that the header and body each be serialized as JSON and then Base64 encoded, and then made “URL safe” by replacing certain characters in the Base64.

  • All trailing = signs should be stripped off.
  • All + characters are turned into - characters.
  • All / characters are turned into _ characters.
  • All leading and trailing whitespace is removed.

After encoding, the URL-safe Base64 encoded head, body, and signature are then concatenated, separated by . characters.

All this might sound kind of arbitrary, but the point is to end up with a token that is easy to put in a URL and that any system understanding JWT can decode back into JSON objects.

Furthermore, any system that has the correct key can verify the signature to prove that the JWT wasn’t forged.

Example: Creating a JWT in Loadster

Here’s an example of crafting a JWT using the HS256 algorithm in a Loadster code block.

function urlSafeBase64 (str) {
    return formats.base64encode(str)
        replace(/=+$/, '').
        replace(/\+/g, '-').
        replace(/\//g, '_').
        trim();
}

function makeSignature (input, algorithm, key) {
    if (algorithm === 'RS256') {
        return urlSafeString(crypto.rsasha256base64(tokenContents, key));
    } else if (algorithm === 'HS256') {
        return urlSafeString(crypto.hmacsha256base64(tokenContents, key));
    } else {
        // check the docs to see if we support your algorithm
    }
}

function makeJWT (header, payload, algorithm, key) {
    const headerString = urlSafeBase64(JSON.stringify(header));
    const payloadString = urlSafeBase64(JSON.stringify(payload));
    const tokenContents = `${headerString}.${payloadString}`;
    const hash = makeSignature(tokenContents, header.alg, key);

    return `${tokenContents}.${hash}`;
}

const jwtHeader = {
    alg: "HS256",
    typ: "JWT"
};

const jwtBody = {
    sub: "1221",
    name: "Dude McBob"
};

makeJWT(jwtHeader, jwtBody, "topSecretCryptoKey");

You could also use a different algorithm like RS256, which requires an RSA key, or some other algorithm if Loadster’s crypto package supports it.