Skip to content

Commit

Permalink
Split NodeJS and browser encodeJwt() functions apart
Browse files Browse the repository at this point in the history
Webpack crashes since it can't find `node:crypto` import
  • Loading branch information
D-Pow committed Aug 6, 2024
1 parent af7eea5 commit 4b17af4
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 17 deletions.
35 changes: 35 additions & 0 deletions config/utils/Crypto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
createHash,
createHmac,
type BinaryLike,
type BinaryToTextEncoding,
} from 'node:crypto';
Expand Down Expand Up @@ -57,3 +58,37 @@ export function hash(input: BinaryLike, {

return cipher.digest(outputFormat as BinaryToTextEncoding);
}



/**
* @see [NodeJS docs]{@link https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options}
* @see [NodeJS walkthrough]{@link https://stackoverflow.com/questions/67432096/generating-jwt-tokens/67432483#67432483}
*/
export function encodeJwt(text: string, {
alg = 'HS256',
typ = 'JWT',
secret = '',
} = {}) {
function base64UrlEncode(str: string) {
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+/g, '');
}

const encodedHeader = base64UrlEncode(JSON.stringify({ alg, typ }));
const encodedPayload = base64UrlEncode(text);
let algorithm = alg
.replace(/^hs/i, 'sha')
.replace(/^\D+/gi, match => match.toLowerCase());

const hmacCipher = createHmac(algorithm, secret);

hmacCipher.update(`${encodedHeader}.${encodedPayload}`);

const hmacStr = hmacCipher.digest('base64url');
const jwt = `${encodedHeader}.${encodedPayload}.${hmacStr}`;

return jwt;
}
1 change: 1 addition & 0 deletions config/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './Network';

// TS
export * from './Certs';
export * from './Crypto';
18 changes: 1 addition & 17 deletions src/utils/Jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,8 @@ export function decodeJwt(jwt: string, {

/**
* Creates a JWT token.
* Works with either NodeJS or modern browsers.
*
* @see [NodeJS walkthrough](https://stackoverflow.com/questions/67432096/generating-jwt-tokens/67432483#67432483)
* @see [Browser walkthrough](https://stackoverflow.com/questions/47329132/how-to-get-hmac-with-crypto-web-api/47332317#47332317)
* @see [Browser walkthrough]{@link https://stackoverflow.com/questions/47329132/how-to-get-hmac-with-crypto-web-api/47332317#47332317}
*/
export async function encodeJwt(text: string, {
alg = 'HS256',
Expand All @@ -117,20 +115,6 @@ export async function encodeJwt(text: string, {
.replace(/^hs/i, 'sha')
.replace(/^\D+/gi, match => match.toLowerCase());

try {
const crypto = await import('node:crypto');
const hmacCipher = crypto.createHmac(algorithm, secret);

hmacCipher.update(`${encodedHeader}.${encodedPayload}`);

const hmacStr = hmacCipher.digest('base64url');
const jwt = `${encodedHeader}.${encodedPayload}.${hmacStr}`;

return jwt;
} catch (notNodeJs) {
// Attempt to use web crypto API below
}

algorithm = algorithm.replace(/^sha/i, 'SHA-');
const algoInfo = {
name: 'HMAC',
Expand Down

0 comments on commit 4b17af4

Please sign in to comment.