feat: major code refactor, add login and register endpoints with swagger
All checks were successful
Update changelog / changelog (push) Successful in 27s
All checks were successful
Update changelog / changelog (push) Successful in 27s
This commit is contained in:
117
src/tools/jwt.ts
Normal file
117
src/tools/jwt.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
// Heavily based on:
|
||||
// https://github.com/TomDoesTech/REST-API-Tutorial-Updated/blob/7b5f040e1acd94d267df585516b33ee7e3b75f70/src/utils/jwt.utils.ts
|
||||
import * as dotenv from 'dotenv';
|
||||
dotenv.config({ quiet: true });
|
||||
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { DEFAULT_TOKEN_LIFETIME } from '../schemas/authSchema';
|
||||
|
||||
type JwtStatus = {
|
||||
valid: boolean;
|
||||
expired: boolean;
|
||||
decoded: string | jwt.JwtPayload | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the environmental string from .env.
|
||||
* Supports rewriting names to UPPER_SNAKE_CASE if isGlobal is set.
|
||||
*
|
||||
* @param {string} key The key
|
||||
* @param {boolean} [isGlobal=true] Indicates if global
|
||||
* @return {(string|undefined)} The environment string.
|
||||
*/
|
||||
export function getEnvString(
|
||||
key: string,
|
||||
isGlobal: boolean = true
|
||||
): string | undefined {
|
||||
let keyName: string = '';
|
||||
|
||||
if (isGlobal) {
|
||||
// Global values are DECLARED_LIKE_THIS=...
|
||||
for (let i: number = 0; i < key.length; i++) {
|
||||
if (key[i].toLowerCase() === key[i]) {
|
||||
// If is lowercase, skip.
|
||||
keyName += key[i];
|
||||
} else {
|
||||
// If is uppercase, convert to snake case.
|
||||
keyName += `_${key[i].toLowerCase()}`;
|
||||
}
|
||||
}
|
||||
keyName.toUpperCase();
|
||||
} else {
|
||||
// Non-global keys are parsed as passed
|
||||
keyName = key;
|
||||
}
|
||||
|
||||
return process.env[keyName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a JWT containing sub (number), role (number, 0/1), iat/exp (unix timestamp) claims.
|
||||
*
|
||||
* @param {Object} object The object
|
||||
* @param {('accessTokenPrivateKey'|'refreshTokenPrivateKey')} keyName The key name
|
||||
* @param {} options?:jwt.SignOptions|undefined The sign options undefined
|
||||
* @return {string} JWT string
|
||||
*/
|
||||
export function signJwt(
|
||||
object: Object,
|
||||
keyName: 'accessTokenPrivateKey' | 'refreshTokenPrivateKey',
|
||||
options?: jwt.SignOptions | undefined
|
||||
): string {
|
||||
|
||||
// refresh tokens aren't (yet) supported
|
||||
// const signingKey = Buffer.from(
|
||||
// process.env[keyName]!,
|
||||
// 'base64'
|
||||
// ).toString('utf8');
|
||||
|
||||
const secret: string = getEnvString(keyName, true)!;
|
||||
|
||||
// Use the default expiration time of 24 hours.
|
||||
if (options === undefined)
|
||||
options = { expiresIn: DEFAULT_TOKEN_LIFETIME };
|
||||
|
||||
return jwt.sign(object, secret, {
|
||||
...options, // (options && options)?
|
||||
// algorithm: 'RS256', // requires a valid private key, not a secret
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a JWT against one of the keys.
|
||||
* Returns JwtStatus, which contains fields for checking validity, expiry and decoded subject claim (id).
|
||||
*
|
||||
* @param {string} token The token
|
||||
* @param {('accessTokenPublicKey'|'refreshTokenPublicKey')} keyName The key name
|
||||
* @return {JwtStatus} JWT status.
|
||||
*/
|
||||
export function verifyJwt(
|
||||
token: string,
|
||||
keyName: 'accessTokenPublicKey' | 'refreshTokenPublicKey'
|
||||
): JwtStatus {
|
||||
|
||||
// refresh tokens aren't (yet) supported
|
||||
// const publicKey = Buffer.from(
|
||||
// process.env[keyName]!,
|
||||
// 'base64'
|
||||
// ).toString('utf8');
|
||||
|
||||
const secret: string = getEnvString(keyName, true)!;
|
||||
|
||||
try {
|
||||
const decoded: string | jwt.JwtPayload = jwt.verify(token, secret);
|
||||
return {
|
||||
valid: true,
|
||||
expired: false,
|
||||
decoded,
|
||||
};
|
||||
} catch (e: any) {
|
||||
console.error('JWT verify error:', e);
|
||||
return {
|
||||
valid: false,
|
||||
expired: e.message === 'jwt expired',
|
||||
decoded: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user