Skip to content

Instantly share code, notes, and snippets.

@whaaaley
Last active August 27, 2022 06:02
Show Gist options
  • Save whaaaley/d2750999decf734dcdc0d0e84abc8cf7 to your computer and use it in GitHub Desktop.
Save whaaaley/d2750999decf734dcdc0d0e84abc8cf7 to your computer and use it in GitHub Desktop.
Compress JWT Payload
import * as crypto from 'node:crypto'
import pako from 'pako'
import basex from 'base-x'
const base16 = basex('0123456789abcdef')
const base62 = basex('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz')
let header = JSON.stringify({ alg: 'HS256', typ: 'JWT' })
header = Buffer.from(header).toString('base64url')
function walkClaims (claims, cb) {
const aud = claims.aud
aud._id = cb(aud._id)
for (let i = 0; i < aud.orgRoles.length; i++) {
const org = aud.orgRoles[i]
org._id = cb(org._id)
for (let j = 0; j < org.projectRoles.length; j++) {
const project = org.projectRoles[j]
project._id = cb(project._id)
}
}
return claims
}
function compressClaims (claims) {
return walkClaims(claims, id => base62.encode(base16.decode(id)))
}
function decompressClaims (claims) {
return walkClaims(claims, id => base16.encode(base62.decode(id)))
}
export function createToken (claims, secret) {
claims = compressClaims(claims) // could be removed safely
const payload = Buffer
.from(pako.deflate(JSON.stringify(claims), { level: 9 })) // with pako
// .from(JSON.stringify(claims), { level: 9 }) // without pako
.toString('base64url')
const headerPayload = header + '.' + payload
const hmac = crypto
.createHmac('sha256', secret)
.update(headerPayload)
.digest('base64url')
return headerPayload + '.' + hmac
}
export function verifyToken (token, secret) {
const [header, payload, signature] = token.split('.')
const newSignature = crypto
.createHmac('sha256', secret)
.update(header + '.' + payload)
.digest('base64url')
if (signature === newSignature) {
let claims = JSON.parse(Buffer
.from(pako.inflate(Buffer.from(payload, 'base64url'))) // with pako
// .from(Buffer.from(payload, 'base64url')) // without pako
.toString())
claims = decompressClaims(claims) // could be removed safely
return claims
}
throw new Error('Token failed to verify')
}
function mongoId () {
return crypto.randomBytes(12).toString('hex')
}
const secret = crypto.randomBytes(256)
const claims = {
exp: Date.now() + 3600000,
aud: {
_id: mongoId(),
orgRoles: [{
_id: mongoId(),
role: 'editor',
projectRoles: [{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
},{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}]
}, {
_id: mongoId(),
role: 'editor',
projectRoles: [{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
},{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}]
}, {
_id: mongoId(),
role: 'editor',
projectRoles: [{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
},{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}]
}, {
_id: mongoId(),
role: 'editor',
projectRoles: [{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
},{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}]
}, {
_id: mongoId(),
role: 'editor',
projectRoles: [{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
},{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}]
}, {
_id: mongoId(),
role: 'editor',
projectRoles: [{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
},{
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}, {
_id: mongoId(),
role: 'admin'
}]
}]
}
}
console.log('')
console.log('--- secret ---')
console.log(secret.toString('hex'))
console.log('')
console.log('--- create token ---')
const token = createToken(claims, secret)
console.log(token)
console.log('token length >>', token.length)
console.log('')
console.log('--- verify token ---')
const restoredClaims = verifyToken(token, secret)
console.log(restoredClaims)
$ node index.js
--- secret ---
21292aaa8126a51c98a78feaf9fbcb0283e7ab994b0d31bd972645304609f236e3981708d43fb8e667658fff84a4a95407c777358b3c72629fe87a764e6987101e60486f96c98f8a27ca576291d862d20db1b0e97533cc9612e74af454394d15c3ee79e393aa8c43c5693ad6d201088f8a2efec2de60df4c79fac8595bb0f9aa529e465c8a785a76bb4561b7088ed419229d130caf5a8d93011ea0ff2e9cec085186e46e63c2767b0b7c2b4ba141b29f51605615b393b7892312caa7dac6f41ba1356649ef33f97cbacff62ed56e0cfbd80afa2af5497ed12f288267d00d085616502b469ac3821563de6785a3d364f78362ef66a00d39da12b19de353def7ef
--- create token ---
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eNqVlEuPozgUhf8L69qAsYHakRBAvMQbwqg14ukAEyBAgFCq_97ZtLrVPbG6Vpblz_a5x-f6gyq3gXqnEaIhD1haYBj4RqX3gnr_oP6tnwMFLe6cRg03iAgw4Qnx1BvVj9jt_ysn6v2fHxgtlZMXiddIwuKFBnr9xMYn81wqi3rux-d8GPumzOfft4JDb2XGOCmGaW6TJ9A_t6bFte6oz7cfaFAtTrncIBZmHXCX7TXJ9LNnTGCxR9NcUks3XqMsB6Q2jkWdKVQnrF2WgAY1H5z0o2dwaECP_P4aBVeblUtunEycPlW30x_ot1_UarMH29FOltY3Arus_t49JsLn0-LmOw0kQUl1SFDP6JjRj0CP5gFxFmwJ6l08SP55mPxdXkczKAmnKnx78Ktuk9ZCHeO0ITwK9DwNhqwo58a9F_iMICBv3T5DS7w7aouTS0myD7qLsAWJw_samh_SAX8hfADqtGEUsq6V6t0dLgRJIHW5SSvGwau07MxIhEIvW7ngh93JwsO8ZcVAOHXOFHmouhIbx1hRZe01CntvCrPFEyIsmGbaB6_RvfGvWX0Y_GRmHkMkEMMXM3QgKDlUtRQ39EP8e_egJST8Pp_Wo9Kdqi4MCXUqbNYmDoD5eCkZw7deo5YHrTrv_dXR6tTdCD4DuStvxa43q9_HILsTssfq4a51rmrPQ2YAj-EIaIMEBgpcWNNYrgfRJroXivrpPhfIhI7Nc0P6hdZt1B25On-7qIe-2mxCSthWvEpLnrlVNm8rmxNSwqjltCayrMT9UVJDmvBJ0mBnPIUNdnSGgreq-Ws02YAilfmg8kZ62z2PcH-KuSbFLNdN7LN5NWL22FsHV_lgtLRyRhB3yxc617Ksu107lbx5eRL1PsG9lF4rxF0uWTOLOFJ4gnodO3HY5sit_WE-nDAhfHzWTw_h5JZH8eBKjvAa3faYzbHbhntjpTeRQAJaCMZdP0cji5gVrcH_uPft8_M7b3lrsA.l68Gj_TiuSKbYY4xAYG9EzoIM2180HWeOjcWRu3T1lQ
token length >> 1075
browser gzip >> 857
--- verify token ---
{
exp: 1661583419225,
aud: {
_id: 'e741bb9d39e9703e001c296d',
orgRoles: [ [Object], [Object], [Object], [Object], [Object], [Object] ]
}
}
$ node index.js
--- secret ---
ffe3d5c790ef4a2e00235e990cd54cf8e6bfca14b9f0f157407b725d9a9226b0c4e2c6fa5e618b156497b7fea56024ead688712e418efd76e09131c192bfe3efb80bab2a87a080217cec4f00c57669659026dde59561e36c35d338cc8c8fc08088d38d714dd8e6947c43bd7781c5b97eabf37783eea8aa49a6296db53384e4603bddb59691845451df91c2d61ccc584ff5d94d9eeb425eddd38950726f4c7178dec4e1fc026b6578dfd5cd0c90294ab7c81c1742ff7e4c123edc13657a76476f6acb2609a14310287969764894e76ef1748d4c5b396fd4824a388ea86dce96b9cd6903ed2c49ccf6cac426067a42f10768e7a060e7fbe3a0d29dea6322386068
--- create token ---
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NjE1ODMzOTE3MzcsImF1ZCI6eyJfaWQiOiI3NmZjNTJlN2JhYWI0ZGY1YjRmOTE2NGYiLCJvcmdSb2xlcyI6W3siX2lkIjoiMWYwMzMyMDkyZWEzY2QzY2JhZDVmZGU1Iiwicm9sZSI6ImVkaXRvciIsInByb2plY3RSb2xlcyI6W3siX2lkIjoiNmVhOTZlMDEwZjgzZWQ2OWRjNzYxOTkzIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiI5NDZlYWY5NzY4MmQwN2JjZGZiMjk4ZTciLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImE1YzUzMzE3NWRjNmIxNGMxMmY1YmU4MiIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiMThkZTA0NDdiN2Q4Y2FhZmIxNDdhNjA0Iiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiI0NzA2MTZjZjRkNWNhYTI4NWZiMDU4ZGIiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6Ijc3MDA4ZTU5YjkzM2MzMzhlNzdkMjE5MyIsInJvbGUiOiJhZG1pbiJ9XX0seyJfaWQiOiIzNWNiNzBhYzhhM2RiMDVkMWRhMTg4NGEiLCJyb2xlIjoiZWRpdG9yIiwicHJvamVjdFJvbGVzIjpbeyJfaWQiOiJjZjVjYTRhNDBiYjQyMGM4MTM1NWZjOGEiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImU5OGNhMDY3ZDJkYWMwMGRiMmU5NzFlYiIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiOWNjMzc5ZmNjYzhlMjhkZjI2NzU1MWJmIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiIxZTFhNTViMGVmOTQ5ZTAwYmUxMmRhMmEiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImU0ODZhZTMyNDNjYmY2YzMyODUwZmJjOCIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiMmE0ODVlMTg5NDY0Yzk3M2E5NzU2YmIyIiwicm9sZSI6ImFkbWluIn1dfSx7Il9pZCI6IjczMDI0Nzk0Njg3ZWViZjkwNjhlZTY3OCIsInJvbGUiOiJlZGl0b3IiLCJwcm9qZWN0Um9sZXMiOlt7Il9pZCI6IjYzYTYzMTg5ZmI5ZjJiY2JiNDQ0ODNkYyIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiZWIzZmI1YTcwZjkxNDczMWEyYzcyYmIwIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiJmYTgyZjlmMTE1NjY5OWU2YTYyMGFlMDEiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImY0N2FiZDRhOGYyMzE0MzRmODBlZWUzOSIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiNGY0MDI3OTY2NjY1OTkyMTdmNGZkM2JlIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiJiNmU2NTVmNjJmYTU5ZWRlNzFiODNlYmMiLCJyb2xlIjoiYWRtaW4ifV19LHsiX2lkIjoiNGU3YzZmZTkyZTVhMTBjNjE5MDIyZTcwIiwicm9sZSI6ImVkaXRvciIsInByb2plY3RSb2xlcyI6W3siX2lkIjoiY2MwMmM0M2YyOTg4YmU2ZTc1ZjhiMWY3Iiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiJhZTgzZjg2MmFkNjFhYTRmOGJiZGMyYTQiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImM5MmFjMDI5ZjQxMmUzNmEwNGQxY2VlYyIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiNGNmNmE2MmNhYWQwMzgxMDQyNmVlNTBhIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiIxYzhlN2YxZjE2MjUzNzUyZjg3MWY0NjgiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6IjI5YTIwZjFjYmE5MTM5NjAyZDcwZDIwZiIsInJvbGUiOiJhZG1pbiJ9XX0seyJfaWQiOiI0MjFlNDNlZjI3Mzc0MzNmMGVlNDZmM2YiLCJyb2xlIjoiZWRpdG9yIiwicHJvamVjdFJvbGVzIjpbeyJfaWQiOiJmODU5MWU2YmI0MGRiYjcwNWIwZGFmNmYiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImIyNzg4ZTAzMTFiNDhhZTVmYmI5OTY4NyIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiNzUyZDkwMzA3YmQ1N2Y5M2E5MjVlOWJjIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiI5ZDBlMjkwMmZkYjU2ZDQwYzZkMTkyNzgiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImFlNTMyYTM5MGEwMzQwNDM1NDYyYzAyNSIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiMWYyZWZmNzdiOTY4MWEyMjliZmVjNGY0Iiwicm9sZSI6ImFkbWluIn1dfSx7Il9pZCI6ImU5ZjI5YjVkOGJlYjgzNDIxZTE0ZTQ4YyIsInJvbGUiOiJlZGl0b3IiLCJwcm9qZWN0Um9sZXMiOlt7Il9pZCI6IjczNGFjNDJjMjIyNjEwZTA1YWUyMjAzNiIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiZTIyZGNhNzJhOGE2NzNjZjVmOTMzMGI3Iiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiJjOTQzNTE2NjViYzk1MTM3NjJiNjI5N2IiLCJyb2xlIjoiYWRtaW4ifSx7Il9pZCI6ImRiMzUxMDdkNjY3OGM4OGY5YTM2YmI4YSIsInJvbGUiOiJhZG1pbiJ9LHsiX2lkIjoiZTRkMGJiOTE4NDUwMDQxZWI3ZjA3NGFjIiwicm9sZSI6ImFkbWluIn0seyJfaWQiOiI0NTc0OWU1OTBlMzRmMDM4OGEwMWYyNDAiLCJyb2xlIjoiYWRtaW4ifV19XX19.nx-uHrDXk4IIMp1zV9ZHG5XtvGLop6DJ8B0juX61BFg
token length >> 3125
browser gzip >> 1322
--- verify token ---
{
exp: 1661583391737,
aud: {
_id: '76fc52e7baab4df5b4f9164f',
orgRoles: [ [Object], [Object], [Object], [Object], [Object], [Object] ]
}
}
@whaaaley
Copy link
Author

whaaaley commented Aug 27, 2022

This test shows that compressing jwt payloads can yield around a 65% savings when using pako.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment