-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt.js
140 lines (124 loc) · 3.36 KB
/
jwt.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
'use strict';
const fs = require('fs-extra');
const crypto = require('crypto');
const util = require('util');
// Regarding generating key pairs in Nodejs, it looks like it is close to being
// part of the crypto module (https://github.com/nodejs/node/pull/22660).
// Creating keys:
// ssh-keygen -t rsa -b 2048 -f node_key.pem
// chmod 600 node_key.pem
// ssh-keygen -f node_key.pem.pub -m 'PEM' -e > node_key.pub.pem
// chmod 600 node_key.pub.pem
const privateKeyPath = '/path';
const publicKeyPath = '/path';
const privateKey = fs.readFileSync(privateKeyPath).toString();
const publicKey = fs.readFileSync(publicKeyPath).toString();
// Expiration date for the jwt.
const yearFromNow = new Date().setFullYear(new Date().getFullYear() + 1);
// Optional: 'secret': 'password',
let payload = {
'issuer': 'mycompany.com',
'kid': 'mycompany.com-001',
'audience': 'someproduct',
'exp': yearFromNow,
'subject': 'some.user'
}
let header = {
'alg': 'RS256',
'typ': 'jwt',
'kid': 'somecompany'
}
function JWT() {
return {
sign: sign,
verify: verify,
}
}
/**
* @param {string} jwt
* @param {string | Object} publicKey
*/
function verify(jwt, publicKey) {
let signature = getJWTSignature(jwt);
// First and second part of JWT string
let headerAndPayload = getHeaderAndPayload(jwt);
// signature = toBase64(signature);
let verifier = crypto.createVerify('RSA-SHA256');
verifier.update(headerAndPayload);
return verifier.verify(publicKey, signature, 'base64');
}
/**
* @param {Object} payload,
* @param {Object} header,
* @param {string} privateKey
*/
function sign(payload, header, privateKey) {
let encodedHeaderPayload = encodeAndFormat(header, payload, 'utf8');
const signer = crypto.createSign('RSA-SHA256');
// Update the Sign content with the given data
signer.update(encodedHeaderPayload)
// Calculates the signature on all the data passed through using either
// sign.update() or sign.write(). Generates and returns a signature.
let signature = signer.sign(privateKey, 'base64');
return util.format('%s.%s', encodedHeaderPayload, signature);
}
/**
*
* @param {Object} header
* @param {Object} payload
* @param {string} encoding
*/
function encodeAndFormat(header, payload, encoding) {
encoding = encoding || 'utf8';
let encodedHeader = base64url(toBuffer(header));
let encodedPayload = base64url(toBuffer(payload));
return util.format('%s.%s', encodedHeader, encodedPayload);
}
/**
*
* @param {Object} val
* @param {string} encoding
*/
function toBuffer(val, encoding) {
if (Buffer.isBuffer(val)) {
return val;
}
if (typeof val === 'string') {
return Buffer.from(val, encoding || 'utf8');
}
if (typeof val === 'number') {
// TODO: Use BigInt() here, to handle large numbers.
val = val.toString();
return Buffer.from(val, 'utf8');
}
return Buffer.from(JSON.stringify(val), 'utf8');
}
/**
*
* @param {Buffer} buf
*/
function base64url(buf) {
return buf
.toString('base64')
.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
/**
*
* @param {string} jwt
*/
function getJWTSignature(jwt) {
return jwt.split('.')[2];
}
/**
*
* @param {string} jwt
*/
function getHeaderAndPayload(jwt) {
return jwt.split('.', 2).join('.');
}
let jwtUtil = JWT();
let jwt = jwtUtil.sign(payload, header, privateKey);
let ver = jwtUtil.verify(jwt, publicKey);
console.log(ver);