Sign and Validate JSON Web Tokens
header: JSON object e.g. {alg:'RS256', typ:'JWT'}
payload: JSON object e.g. {isAdmin: false}
PRIVATE_KEY_PATH: String that represents the private key that shall be used for signing the access-token, e.g. 'jwtRS256.key'
maxAgeMinutes: Number representing the access-token lifetime, e.g. 60
trustedTenant: String identifier for whom signed the access-token, e.g. 'http://example.com'
useJti: Boolean value that if set to "true" will treat JWTs as "one-time-tokens" and add a psuedo random cryptographic string to the jti claim, which acts as a nonce (number occuring once)
audience: String used to describe the URL/ endpoint of which the refresh-token can be used to obtain new access-tokens
const result = await jwtSign(
header,
payload,
PRIVATE_KEY_PATH,
30,
trustedTenant,
'false',
audience
);
if (result.error || result.e) res.status(401).json({ error: isValid });
console.log(result.accessToken, result.refreshToken);
res.status(200).json(resource);
jwt: base64Url encoded JWT to be validated
validAlgorithm: Array containing the algorithm used to sign the JWT
trustedIssuer: String describing the expected issuer of the JWT, e.g. 'http://example.com'
PUBLIC_KEY_PATH: String that represents the private key's corresponding public key that shall be used for verifying the integrity of access-tokens, e.g. 'jwtRS256.key.pub'
const result = await jwtVerify(
jwt,
validAlgorithm,
trustedIssuer,
PUBLIC_KEY_PATH,
'false'
);
if (result !== true) return { error: result.error };
res.status(200).json(resource);
Generate a public/private key pair of size 4096 using the RSA algorithm
ssh-keygen -t rsa -b 4096 -m PEM -f RS256.key
openssl rsa -in RS256.key -pubout -outform PEM -out RS256.key.pub
install express (web server), morgan (http-logger) and the library (sign and validate JWTs)
npm install morgan express first-test-lib-jwt-do-not-use
const express = require('express');
const app = express();
const morgan = require('morgan');
const jwtSign = require('./node_modules/first-test-lib-jwt-do-not-use/jwt/jwtSign');
const jwtVerify = require('./node_modules/first-test-lib-jwt-do-not-use/jwt/jwtVerify');
const PORT = 3000;
const DB = { username: 'bob', password: 'secret', isAdmin: true };
app.use(morgan('dev'));
app.use(express.json());
const PRIVATE_KEY_PATH = 'jwtRS256.key';
const PUBLIC_KEY_PATH = 'jwtRS256.key.pub';
const validAlgorithm = ['RS256'];
const trustedTenant = `http://127.0.0.1:${PORT}`;
const aud = `http://127.0.0.1:${PORT}/refresh-token`;
app.post('/login', async (req, res) => {
try {
if (
req.body.username !== DB.username ||
req.body.password !== DB.password
) {
return res
.status(401)
.json({ Unauthorized: 'your credentials did not match DB' });
}
const header = { alg: 'RS256', typ: 'JWT' };
const payload = { username: DB.username, isAdmin: DB.isAdmin };
const jwt = await jwtSign(
header,
payload,
PRIVATE_KEY_PATH,
30,
trustedTenant,
'false',
aud
);
if (!jwt.accessToken || !jwt.refreshToken) {
return res.status(401).json(jwt);
}
return res.append('Authorization', jwt.accessToken).status(200).json(jwt);
} catch (e) {
res.json(e);
}
});
app.get('/resource', async (req, res) => {
try {
const accessToken = JSON.stringify(req.headers.authorization);
if (!accessToken)
return res.status(401).json({
Unauthorized: 'access-token needs to be a part of the request header!',
});
const isValid = await jwtVerify(
accessToken,
validAlgorithm,
trustedTenant,
PUBLIC_KEY_PATH,
'false'
);
if (isValid === true) {
return res.status(200).json({ resource: 'resource' });
} else {
return res.status(401).json({ error: isValid });
}
} catch (e) {
return res.status(400).json(e);
}
});
app.listen(PORT, () => console.log(`Server listening to ${PORT}`));