From e982fd07bfd3354c108efc14775d03087e816651 Mon Sep 17 00:00:00 2001 From: Haris Chaniotakis Date: Tue, 18 Jan 2022 17:52:13 +0200 Subject: [PATCH] fix(clerk-sdk-node): Properly import key from jwk --- packages/sdk-node/src/Clerk.ts | 15 +++++---------- packages/sdk-node/src/utils/crypto.ts | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 packages/sdk-node/src/utils/crypto.ts diff --git a/packages/sdk-node/src/Clerk.ts b/packages/sdk-node/src/Clerk.ts index ba7537d5c29..17e2812d325 100644 --- a/packages/sdk-node/src/Clerk.ts +++ b/packages/sdk-node/src/Clerk.ts @@ -36,12 +36,10 @@ export type RequireSessionClaimsProp = T & { sessionClaims: JwtPayload }; import { Base } from '@clerk/backend-core'; import { Crypto, CryptoKey } from '@peculiar/webcrypto'; +import { decodeBase64, toSPKIDer } from './utils/crypto'; const crypto = new Crypto(); -const decodeBase64 = (base64: string) => - Buffer.from(base64, 'base64').toString('binary'); - const importKey = async (jwk: JsonWebKey, algorithm: Algorithm) => { return await crypto.subtle.importKey('jwk', jwk, algorithm, true, ['verify']); }; @@ -123,15 +121,12 @@ export default class Clerk extends ClerkBackendAPI { cacheMaxAge: jwksCacheMaxAge, }); - const encoder = new TextEncoder(); + const signingKey = await jwksClient.getSigningKey(decoded.header.kid) + const pubKey = signingKey.getPublicKey() return await crypto.subtle.importKey( - 'raw', - encoder.encode( - ( - await jwksClient.getSigningKey(decoded.header.kid) - ).getPublicKey() as string - ), + 'spki', + toSPKIDer(pubKey), { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256', diff --git a/packages/sdk-node/src/utils/crypto.ts b/packages/sdk-node/src/utils/crypto.ts new file mode 100644 index 00000000000..d52261c2a4b --- /dev/null +++ b/packages/sdk-node/src/utils/crypto.ts @@ -0,0 +1,21 @@ +export const decodeBase64 = (base64: string) => + Buffer.from(base64, 'base64').toString('binary'); + +// toSPKIDer converts a PEM encoded Public Key to DER encoded +export function toSPKIDer(pem: string): ArrayBuffer { + const pemHeader = "-----BEGIN PUBLIC KEY-----"; + const pemFooter = "-----END PUBLIC KEY-----"; + const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length); + const binaryDerString = decodeBase64(pemContents) + return str2ab(binaryDerString); +} + +// https://stackoverflow.com/a/11058858 +function str2ab(input: string): ArrayBuffer { + const buf = new ArrayBuffer(input.length); + const bufView = new Uint8Array(buf); + for (let i = 0, strLen = input.length; i < strLen; i++) { + bufView[i] = input.charCodeAt(i); + } + return buf; +}