JWT

JSON Web Token

a Base64 encoded JSON object

with a cryptographic signature

Login

Regular Request

Inter Service

Benefits

  • fewer database operations
  • lower latency
  • better scalability

 

Usable in

  • URL:s
  • HTTP headers (Bearer)
  • HTTP body (application/jwt)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
{
  "alg": "HS256",
  "typ": "JWT"
}
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
const data = 
const key = crypto.subtle.importKey("raw", key, 
	{ name: "HMAC", hash: { name: "SHA-" + this.length } },
	false, [ "sign", "verify" ])

const signature = await crypto.subtle.sign("HMAC", await key, data)
const header = {
  alg: "HS256",
  typ: "JWT"
}

Issue Token

const payload = {
  sub: "1234567890",
  name: "John Doe",
  iat: 1516239022
}
const data = Base64.encode(new TextEncoder().encode(JSON.stringify(header))) + "." + 
	Base64.encode(new TextEncoder().encode(JSON.stringify(payload)))

const key = crypto.subtle.importKey("raw", key,
	{ name: "HMAC", hash: { name: "SHA-" + this.length } }, false,[ "sign", "verify" ])

const signature = await crypto.subtle.sign("HMAC", await key, data)
const token = data + "." + signature

Header

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

algorithms:

  • none
  • HS - HMAC
  • RS - RSA
  • ES
  • PS
  • EdDSA - CFRG Elliptic Curve Signatures - RFC8037

bit lengths:

  • 256
  • 384
  • 512

Payload Claims

Registered Claims:

  • iss - issuer
  • sub - subject
  • aud - audience
  • exp - expiration time
  • nbf - not before
  • iat - issued at
  • jti - JWT ID

Authly

github.com/payfunc/authly · MIT license

Benefits

  • supports browser and Node.js
  • verifies alg header
  • encrypted properties

Drawbacks

  • few users
  • binary dependency when using Node.JS

Signature Algorithms

  • None
  • HMAC - HS256, HS384, HS512
  • RSA - RS256, RS384, RS512

Usage

import * as authly from "authly"

const algorithm = authly.Algorithm.HS256(process.env.apiKeySecret)
const verifier = authly.Verifier.create("audience", algorithm)
const issuer = authly.Issuer.create("issuer", algorithm)

const token = await issuer.issue({
  sub: "1234567890",
  name: "John Doe",
  admin: true,
  iat: 1516239022,
  aud: "audience"
})

const payload = await verifier.verify(token)
npm install -S authly

Property Encryption

import * as authly from "authly"

const algorithm = authly.Algorithm.HS256(process.env.apiKeySecret)
const verifier = authly.Verifier.create("audience", algorithm).add(process.env.propertySecret, "property0", "property1")
const issuer = authly.Issuer.create("issuer", algorithm).add(process.env.propertySecret, "property0", "property2")

const token = await issuer.issue(payload)

const payload = await verifier.verify(token)

Usage

Encryption

const secret = this.secret + payload.sub + payload.iat + property.join(".")
const key = new Uint8Array(await crypto.subtle.digest("SHA-512", new TextEncoder().encode(secret)))

const data = preprocess(payload[property[0]])
const processed = new Uint8Array(data.length)
for (let index = 0; index < data.length; index++)
	processed[index] = data[index] ^ key[index]
result = postprocess(processed)

Limitation

property must be shorter then 512 bits

PayFunc Usage

API Key

  • public vs private audience
  • contains all useful merchant configuration
  • property encryption for back end credentials

Signing Orders

  • merchant sets number
  • successfull orders signed
  • public key signature

References