Skip to content

Instantly share code, notes, and snippets.

@MarcelloTheArcane
Created January 20, 2020 13:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MarcelloTheArcane/34cb57b4e057616336f42a7ad152c97c to your computer and use it in GitHub Desktop.
Save MarcelloTheArcane/34cb57b4e057616336f42a7ad152c97c to your computer and use it in GitHub Desktop.
Blockchain with JWT

Example Ledger

When decoded, each block refers to the previous block in the chain.

  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ2MS4wLjAiLCJpYXQiOjE1Nzk1MTU2MTcsInNpZyI6IiIsImRhdCI6e319.rqmyHA3pgvwSLPS7Arj2pz3KS5rK14ZJNHv3BCAB2b4
{
  "iss": "v1.0.0",
  "iat": 1579515617,
  "sig": "",
  "dat": {}
}
  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ2MS4wLjAiLCJpYXQiOjE1Nzk1MTY5MzksInNpZyI6InJxbXlIQTNwZ3Z3U0xQUzdBcmoycHozS1M1cksxNFpKTkh2M0JDQUIyYjQiLCJkYXQiOnsibWVzc2FnZSI6IlRoaXMgaXMgdGhlIGZpcnN0IGdlbmVyYXRlZCBibG9jayEifX0.ZE-S8vKJqU-PKJdNaXpBhl3632GQOpxZJFGziY1LSc4
{
  "iss": "v1.0.0",
  "iat": 1579516939,
  "sig": "rqmyHA3pgvwSLPS7Arj2pz3KS5rK14ZJNHv3BCAB2b4",
  "dat": {
    "message": "This is the first generated block!"
  }
}
  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ2MS4wLjAiLCJpYXQiOjE1Nzk1MTcwMDAsInNpZyI6IlpFLVM4dktKcVUtUEtKZE5hWHBCaGwzNjMyR1FPcHhaSkZHemlZMUxTYzQiLCJkYXQiOnsibWVzc2FnZSI6IkFuZCB3ZSBjYW4gc3RvcmUgYW55IEpTT04gZGF0YS4ifX0.wSkBOIdUzZgVom4_Dz8RmE8buiJnd4up5PksIT72IRA
{
  "iss": "v1.0.0",
  "iat": 1579517000,
  "sig": "ZE-S8vKJqU-PKJdNaXpBhl3632GQOpxZJFGziY1LSc4",
  "dat": {
    "message": "And we can store any JSON data."
  }
}
  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ2MS4wLjAiLCJpYXQiOjE1Nzk1MTcwMTksInNpZyI6IndTa0JPSWRVelpnVm9tNF9EejhSbUU4YnVpSm5kNHVwNVBrc0lUNzJJUkEiLCJkYXQiOnsibWVzc2FnZSI6IllvdSBzaG91bGQgcGFyc2UgYGRhdGAgYmFzZWQgb24gdGhlIHVuaXF1ZSBgaXNzYC4gQW55dGhpbmcgaXMgcG9zc2libGUhIn19.F6222nCVGy5JieDlDK_ROwZWrJov1VjvjRhs5YXFS-4
{
  "iss": "v1.0.0",
  "iat": 1579517019,
  "sig": "wSkBOIdUzZgVom4_Dz8RmE8buiJnd4up5PksIT72IRA",
  "dat": {
    "message": "You should parse `dat` based on the unique `iss`. Anything is possible!"
  }
}
// Extremely simple blockchain service
// Needs implementation of JWT service, so it automatically calculates next JWT in chain
interface Token {
iss: string
iat: number
sig: string
dat: any
}
interface Blockchain {
add: (data: string) => void
getStore: () => string[]
getLastBlockSignature: () => string
getBlockData: (index: number) => Token
}
function JWTBlockchain (genesis: string): Blockchain {
const _store: [string] = [genesis]
function _validate (candidate: string): boolean {
try {
const lastBlock: string = _store[_store.length - 1]
const parsedLastBlock: Token = JSON.parse(atob(lastBlock.split('.')[1]))
const lastBlockSignature: string = getLastBlockSignature()
const parsedCandidate: Token = JSON.parse(atob(candidate.split('.')[1]))
const versionMatches: boolean = parsedCandidate.iss === parsedLastBlock.iss
const signatureMatches: boolean = parsedCandidate.sig === lastBlockSignature
const issuedLater: boolean = parsedCandidate.iat > parsedLastBlock.iat
if (versionMatches && signatureMatches && issuedLater) {
return true
} else {
return false
}
} catch (err) {
return false
}
}
function add (data: string): void {
if (_validate(data)) {
_store.push(data)
}
}
function getStore (): string[] {
return _store.slice()
}
function getLastBlockSignature (): string {
return _store[_store.length - 1].split('.')[2]
}
function getBlockData (index: number): Token {
if (index >= 0 && index <= _store.length - 1 && index % 1 === 0) {
return JSON.parse(atob(_store[index].split('.')[1]))
}
}
return {
add,
getStore,
getLastBlockSignature,
getBlockData,
}
}
// const blockchain = JWTBlockchain(<initial jwt>)
// blockchain.add(<next jwt in chain>)

Genesis Block (index #0):

The implementation must start with a Genesis Block, which is the block that all other blocks derive from.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ2MS4wLjAiLCJpYXQiOjE1Nzk1MTU2MTcsInNpZyI6IiIsImRhdCI6e319.rqmyHA3pgvwSLPS7Arj2pz3KS5rK14ZJNHv3BCAB2b4
{
  "alg": "HS256",
  "typ": "JWT"
}

{
  "iss": "v1.0.0",
  "iat": 1579515617,
  "sig": "",
  "idx": 0,
  "dat": {}
}

Keys

  • iss is a Registered Claim, and 'identifies the principal that issued the JWT'. This will enable correct parsing of the dat key below.
  • iat is a Registered Claim, and 'identifies the time at which the JWT was issued.'
  • sig is the key to the blockchain. It refers to the previous JWT's signature.
  • dat is where the data is stored in the chain. Its schema is defined by the version number in the iss key above. An arbitrary JSON payload can be stored, including validation for Proof of Work

Proof of work

A proof-of-work (PoW) system (or protocol, or function) is a consensus mechanism. It deters denial-of-service attacks and other service abuses such as spam on a network by requiring some work from the service requester, usually meaning processing time by a computer. - Wikipedia

With a publicly-distributed ledger, strenuous PoW algorithms should be used (i.e. finding a hash with a specified number of 0 prepending the hash, for example 0000000000000756af69e2ffbdb930261873cd71.

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