├── .gitignore ├── README.md ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bitclout-jwt-validate 2 | 3 | This project is a simple javascript/node.js example to help validate & decode a BitClout JWT token using a BitClout public key 4 | 5 | This was created based on the BitClout identity docs example of how to validate a JWT token (https://docs.bitclout.com/devs/identity-api#validation-in-go). I struggled to get validation working solely based on the docs so I thought this example might help others. 6 | 7 | Feel free to reach out to [@mattetre](https://bitclout.com/u/mattetre) from [@bithunt](https://bitclout.com/u/bithunt) 8 | 9 | ## BitClout public key info 10 | 11 | What I found in my testing is that the BitClout public key is not the public key that you get from the original keypair that is used to sign the your JWT. It has been manipulated to add in a "prefix" and then base58 encoded. If you want to validate your JWT you need to decode your public key and then remove the prefix to obtain the original public key. This removal of the prefix was not obvious for me looking at the BitClout identity docs. 12 | 13 | See for more info: `privateKeyToBitcloutPublicKey` in https://github.com/bitclout/identity/blob/main/src/app/crypto.service.ts#L128 14 | 15 | ## Running the code 16 | 17 | ### Setup 18 | 19 | install dependencies 20 | 21 | ```shell 22 | npm install 23 | ``` 24 | 25 | ### Running 26 | 27 | ```shell 28 | node index.js --publicKey BITCLOUT_PUBLIC_KEY --jwt JWT_TOKEN 29 | ``` 30 | 31 | ```shell 32 | node index.js -p BITCLOUT_PUBLIC_KEY -j JWT_TOKEN 33 | ``` 34 | 35 | example: 36 | 37 | ```shell 38 | node.js index.js --publicKey abc123 --jwt 321xyz 39 | ``` 40 | 41 | ## Credits: 42 | 43 | Thanks [@mubashariqbal](https://bitclout.com/u/mubashariqbal) and [@transhumanist](https://bitclout.com/u/transhumanist) for your code getting BitClout identiy working on web! 44 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const yargs = require("yargs"); 2 | const jsonwebtoken = require("jsonwebtoken"); 3 | const EC = require("elliptic").ec; 4 | const ec = new EC("secp256k1"); 5 | const KeyEncoder = require("key-encoder").default; 6 | const bs58check = require("bs58check"); 7 | 8 | const argv = yargs 9 | .option("publicKey", { 10 | alias: "p", 11 | description: "Bitclout Public Key", 12 | type: "string", 13 | }) 14 | .option("jwt", { 15 | alias: "j", 16 | description: "Bitclout JWT token", 17 | type: "string", 18 | }) 19 | // .describe('f', 'Load a file') 20 | .demandOption(["j", "p"]) 21 | .help() 22 | .alias("help", "h").argv; 23 | 24 | const bitCloutPublicKey = argv.publicKey; 25 | const jwtToken = argv.jwt; 26 | 27 | const result = validateJwt(bitCloutPublicKey, jwtToken); 28 | console.log(result); 29 | 30 | function validateJwt(bitCloutPublicKey, jwtToken) { 31 | const bitCloutPublicKeyDecoded = bs58check.decode(bitCloutPublicKey); 32 | 33 | // manipulate the decoded key to remove the prefix that gets added 34 | // see: privateKeyToBitcloutPublicKey - https://github.com/bitclout/identity/blob/main/src/app/crypto.service.ts#L128 35 | 36 | // turn buffer into an array to easily manipulate 37 | const bitCloutPublicKeyDecodedArray = [...bitCloutPublicKeyDecoded]; 38 | // Remove the public key prefix to get the 'raw public key' 39 | // not sure if hardcoding this to 3 elements is safe 40 | // see: PUBLIC_KEY_PREFIXES - https://github.com/bitclout/identity/blob/main/src/app/crypto.service.ts#L22 41 | const rawPublicKeyArray = bitCloutPublicKeyDecodedArray.slice(3); 42 | 43 | const rawPublicKeyHex = ec 44 | .keyFromPublic(rawPublicKeyArray, "hex") 45 | .getPublic() 46 | .encode("hex", true); 47 | 48 | const keyEncoder = new KeyEncoder("secp256k1"); 49 | const rawPublicKeyEncoded = keyEncoder.encodePublic( 50 | rawPublicKeyHex, 51 | "raw", 52 | "pem" 53 | ); 54 | 55 | // if the jwt or public key is invalid this will throw an error 56 | const result = jsonwebtoken.verify(jwtToken, rawPublicKeyEncoded, { 57 | algorithms: ["ES256"], 58 | }); 59 | return result; 60 | } 61 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitclout-jwt-validate", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/bn.js": { 8 | "version": "5.1.0", 9 | "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", 10 | "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", 11 | "requires": { 12 | "@types/node": "*" 13 | } 14 | }, 15 | "@types/elliptic": { 16 | "version": "6.4.12", 17 | "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.12.tgz", 18 | "integrity": "sha512-gP1KsqoouLJGH6IJa28x7PXb3cRqh83X8HCLezd2dF+XcAIMKYv53KV+9Zn6QA561E120uOqZBQ+Jy/cl+fviw==", 19 | "requires": { 20 | "@types/bn.js": "*" 21 | } 22 | }, 23 | "@types/node": { 24 | "version": "15.0.2", 25 | "resolved": "https://registry.npmjs.org/@types/node/-/node-15.0.2.tgz", 26 | "integrity": "sha512-p68+a+KoxpoB47015IeYZYRrdqMUcpbK8re/zpFB8Ld46LHC1lPEbp3EXgkEhAYEcPvjJF6ZO+869SQ0aH1dcA==" 27 | }, 28 | "ansi-regex": { 29 | "version": "5.0.0", 30 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", 31 | "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" 32 | }, 33 | "ansi-styles": { 34 | "version": "4.3.0", 35 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 36 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 37 | "requires": { 38 | "color-convert": "^2.0.1" 39 | } 40 | }, 41 | "asn1.js": { 42 | "version": "5.4.1", 43 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", 44 | "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", 45 | "requires": { 46 | "bn.js": "^4.0.0", 47 | "inherits": "^2.0.1", 48 | "minimalistic-assert": "^1.0.0", 49 | "safer-buffer": "^2.1.0" 50 | } 51 | }, 52 | "base-x": { 53 | "version": "3.0.8", 54 | "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", 55 | "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", 56 | "requires": { 57 | "safe-buffer": "^5.0.1" 58 | } 59 | }, 60 | "bn.js": { 61 | "version": "4.12.0", 62 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", 63 | "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" 64 | }, 65 | "brorand": { 66 | "version": "1.1.0", 67 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 68 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" 69 | }, 70 | "bs58": { 71 | "version": "4.0.1", 72 | "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", 73 | "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", 74 | "requires": { 75 | "base-x": "^3.0.2" 76 | } 77 | }, 78 | "bs58check": { 79 | "version": "2.1.2", 80 | "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", 81 | "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", 82 | "requires": { 83 | "bs58": "^4.0.0", 84 | "create-hash": "^1.1.0", 85 | "safe-buffer": "^5.1.2" 86 | } 87 | }, 88 | "buffer-equal-constant-time": { 89 | "version": "1.0.1", 90 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 91 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 92 | }, 93 | "cipher-base": { 94 | "version": "1.0.4", 95 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", 96 | "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", 97 | "requires": { 98 | "inherits": "^2.0.1", 99 | "safe-buffer": "^5.0.1" 100 | } 101 | }, 102 | "cliui": { 103 | "version": "7.0.4", 104 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 105 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 106 | "requires": { 107 | "string-width": "^4.2.0", 108 | "strip-ansi": "^6.0.0", 109 | "wrap-ansi": "^7.0.0" 110 | } 111 | }, 112 | "color-convert": { 113 | "version": "2.0.1", 114 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 115 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 116 | "requires": { 117 | "color-name": "~1.1.4" 118 | } 119 | }, 120 | "color-name": { 121 | "version": "1.1.4", 122 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 123 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 124 | }, 125 | "create-hash": { 126 | "version": "1.2.0", 127 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", 128 | "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", 129 | "requires": { 130 | "cipher-base": "^1.0.1", 131 | "inherits": "^2.0.1", 132 | "md5.js": "^1.3.4", 133 | "ripemd160": "^2.0.1", 134 | "sha.js": "^2.4.0" 135 | } 136 | }, 137 | "ecdsa-sig-formatter": { 138 | "version": "1.0.11", 139 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 140 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 141 | "requires": { 142 | "safe-buffer": "^5.0.1" 143 | } 144 | }, 145 | "elliptic": { 146 | "version": "6.5.4", 147 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", 148 | "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", 149 | "requires": { 150 | "bn.js": "^4.11.9", 151 | "brorand": "^1.1.0", 152 | "hash.js": "^1.0.0", 153 | "hmac-drbg": "^1.0.1", 154 | "inherits": "^2.0.4", 155 | "minimalistic-assert": "^1.0.1", 156 | "minimalistic-crypto-utils": "^1.0.1" 157 | } 158 | }, 159 | "emoji-regex": { 160 | "version": "8.0.0", 161 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 162 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 163 | }, 164 | "escalade": { 165 | "version": "3.1.1", 166 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 167 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 168 | }, 169 | "get-caller-file": { 170 | "version": "2.0.5", 171 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 172 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" 173 | }, 174 | "hash-base": { 175 | "version": "3.1.0", 176 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", 177 | "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", 178 | "requires": { 179 | "inherits": "^2.0.4", 180 | "readable-stream": "^3.6.0", 181 | "safe-buffer": "^5.2.0" 182 | } 183 | }, 184 | "hash.js": { 185 | "version": "1.1.7", 186 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 187 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 188 | "requires": { 189 | "inherits": "^2.0.3", 190 | "minimalistic-assert": "^1.0.1" 191 | } 192 | }, 193 | "hmac-drbg": { 194 | "version": "1.0.1", 195 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 196 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 197 | "requires": { 198 | "hash.js": "^1.0.3", 199 | "minimalistic-assert": "^1.0.0", 200 | "minimalistic-crypto-utils": "^1.0.1" 201 | } 202 | }, 203 | "inherits": { 204 | "version": "2.0.4", 205 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 206 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 207 | }, 208 | "is-fullwidth-code-point": { 209 | "version": "3.0.0", 210 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 211 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" 212 | }, 213 | "jsonwebtoken": { 214 | "version": "8.5.1", 215 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", 216 | "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", 217 | "requires": { 218 | "jws": "^3.2.2", 219 | "lodash.includes": "^4.3.0", 220 | "lodash.isboolean": "^3.0.3", 221 | "lodash.isinteger": "^4.0.4", 222 | "lodash.isnumber": "^3.0.3", 223 | "lodash.isplainobject": "^4.0.6", 224 | "lodash.isstring": "^4.0.1", 225 | "lodash.once": "^4.0.0", 226 | "ms": "^2.1.1", 227 | "semver": "^5.6.0" 228 | } 229 | }, 230 | "jwa": { 231 | "version": "1.4.1", 232 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 233 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 234 | "requires": { 235 | "buffer-equal-constant-time": "1.0.1", 236 | "ecdsa-sig-formatter": "1.0.11", 237 | "safe-buffer": "^5.0.1" 238 | } 239 | }, 240 | "jws": { 241 | "version": "3.2.2", 242 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 243 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 244 | "requires": { 245 | "jwa": "^1.4.1", 246 | "safe-buffer": "^5.0.1" 247 | } 248 | }, 249 | "key-encoder": { 250 | "version": "2.0.3", 251 | "resolved": "https://registry.npmjs.org/key-encoder/-/key-encoder-2.0.3.tgz", 252 | "integrity": "sha512-fgBtpAGIr/Fy5/+ZLQZIPPhsZEcbSlYu/Wu96tNDFNSjSACw5lEIOFeaVdQ/iwrb8oxjlWi6wmWdH76hV6GZjg==", 253 | "requires": { 254 | "@types/elliptic": "^6.4.9", 255 | "asn1.js": "^5.0.1", 256 | "bn.js": "^4.11.8", 257 | "elliptic": "^6.4.1" 258 | } 259 | }, 260 | "lodash.includes": { 261 | "version": "4.3.0", 262 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 263 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 264 | }, 265 | "lodash.isboolean": { 266 | "version": "3.0.3", 267 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 268 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 269 | }, 270 | "lodash.isinteger": { 271 | "version": "4.0.4", 272 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 273 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 274 | }, 275 | "lodash.isnumber": { 276 | "version": "3.0.3", 277 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 278 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 279 | }, 280 | "lodash.isplainobject": { 281 | "version": "4.0.6", 282 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 283 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 284 | }, 285 | "lodash.isstring": { 286 | "version": "4.0.1", 287 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 288 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 289 | }, 290 | "lodash.once": { 291 | "version": "4.1.1", 292 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 293 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 294 | }, 295 | "md5.js": { 296 | "version": "1.3.5", 297 | "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", 298 | "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", 299 | "requires": { 300 | "hash-base": "^3.0.0", 301 | "inherits": "^2.0.1", 302 | "safe-buffer": "^5.1.2" 303 | } 304 | }, 305 | "minimalistic-assert": { 306 | "version": "1.0.1", 307 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 308 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" 309 | }, 310 | "minimalistic-crypto-utils": { 311 | "version": "1.0.1", 312 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 313 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" 314 | }, 315 | "ms": { 316 | "version": "2.1.3", 317 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 318 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 319 | }, 320 | "readable-stream": { 321 | "version": "3.6.0", 322 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 323 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 324 | "requires": { 325 | "inherits": "^2.0.3", 326 | "string_decoder": "^1.1.1", 327 | "util-deprecate": "^1.0.1" 328 | } 329 | }, 330 | "require-directory": { 331 | "version": "2.1.1", 332 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 333 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" 334 | }, 335 | "ripemd160": { 336 | "version": "2.0.2", 337 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", 338 | "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", 339 | "requires": { 340 | "hash-base": "^3.0.0", 341 | "inherits": "^2.0.1" 342 | } 343 | }, 344 | "safe-buffer": { 345 | "version": "5.2.1", 346 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 347 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 348 | }, 349 | "safer-buffer": { 350 | "version": "2.1.2", 351 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 352 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 353 | }, 354 | "semver": { 355 | "version": "5.7.1", 356 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 357 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 358 | }, 359 | "sha.js": { 360 | "version": "2.4.11", 361 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", 362 | "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", 363 | "requires": { 364 | "inherits": "^2.0.1", 365 | "safe-buffer": "^5.0.1" 366 | } 367 | }, 368 | "string-width": { 369 | "version": "4.2.2", 370 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", 371 | "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", 372 | "requires": { 373 | "emoji-regex": "^8.0.0", 374 | "is-fullwidth-code-point": "^3.0.0", 375 | "strip-ansi": "^6.0.0" 376 | } 377 | }, 378 | "string_decoder": { 379 | "version": "1.3.0", 380 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 381 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 382 | "requires": { 383 | "safe-buffer": "~5.2.0" 384 | } 385 | }, 386 | "strip-ansi": { 387 | "version": "6.0.0", 388 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", 389 | "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", 390 | "requires": { 391 | "ansi-regex": "^5.0.0" 392 | } 393 | }, 394 | "util-deprecate": { 395 | "version": "1.0.2", 396 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 397 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 398 | }, 399 | "wrap-ansi": { 400 | "version": "7.0.0", 401 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 402 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 403 | "requires": { 404 | "ansi-styles": "^4.0.0", 405 | "string-width": "^4.1.0", 406 | "strip-ansi": "^6.0.0" 407 | } 408 | }, 409 | "y18n": { 410 | "version": "5.0.8", 411 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 412 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" 413 | }, 414 | "yargs": { 415 | "version": "17.0.1", 416 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", 417 | "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", 418 | "requires": { 419 | "cliui": "^7.0.2", 420 | "escalade": "^3.1.1", 421 | "get-caller-file": "^2.0.5", 422 | "require-directory": "^2.1.1", 423 | "string-width": "^4.2.0", 424 | "y18n": "^5.0.5", 425 | "yargs-parser": "^20.2.2" 426 | } 427 | }, 428 | "yargs-parser": { 429 | "version": "20.2.7", 430 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", 431 | "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==" 432 | } 433 | } 434 | } 435 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitclout-jwt-validate", 3 | "version": "1.0.0", 4 | "description": "sample code to validate a bitclout JWT", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/mattetre/bitclout-jwt-validate.git" 12 | }, 13 | "keywords": [ 14 | "bitclout", 15 | "jwt", 16 | "identity" 17 | ], 18 | "author": "mattetre", 19 | "homepage": "https://github.com/mattetre/bitclout-jwt-validate#readme", 20 | "dependencies": { 21 | "bs58check": "^2.1.2", 22 | "elliptic": "^6.5.4", 23 | "jsonwebtoken": "^8.5.1", 24 | "key-encoder": "^2.0.3", 25 | "yargs": "^17.0.1" 26 | } 27 | } 28 | --------------------------------------------------------------------------------