From cd202e9a7015f8dcec0ca5e8007841d40403090b Mon Sep 17 00:00:00 2001 From: Stepan Kazakov Date: Sun, 2 Mar 2025 11:54:49 +0300 Subject: [PATCH] feat(iam-token-service): replace jsonwebtoken with jose --- examples/package-lock.json | 3 +- package-lock.json | 138 +++++-------------------- package.json | 3 +- src/token-service/iam-token-service.ts | 36 ++++--- 4 files changed, 48 insertions(+), 132 deletions(-) diff --git a/examples/package-lock.json b/examples/package-lock.json index 2e20b064..23526ec3 100644 --- a/examples/package-lock.json +++ b/examples/package-lock.json @@ -23,7 +23,7 @@ "dependencies": { "@grpc/grpc-js": "https://gitpkg.now.sh/DavyJohnes/grpc-node/packages/grpc-js?fix-class-options-issue-with-dist", "axios": "^0.24.0", - "jsonwebtoken": "^8.5.1", + "jose": "^6.0.8", "lodash": "^4.17.21", "log4js": "^6.3.0", "long": "^5.2.0", @@ -38,7 +38,6 @@ "@commitlint/config-conventional": "^15.0.0", "@semantic-release/git": "^10.0.1", "@types/jest": "^27.0.3", - "@types/jsonwebtoken": "^8.5.6", "@types/lodash": "^4.14.178", "@types/luxon": "^2.0.8", "@types/node": "^16.11.3", diff --git a/package-lock.json b/package-lock.json index c85757f1..62299c14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@grpc/grpc-js": "^1.6.12", "abort-controller-x": "^0.4.1", "axios": "^0.28.0", - "jsonwebtoken": "^9.0.0", + "jose": "^6.0.8", "lodash": "^4.17.21", "log4js": "^6.4.0", "long": "^5.2.0", @@ -28,7 +28,6 @@ "@commitlint/config-conventional": "^15.0.0", "@semantic-release/git": "^10.0.1", "@types/jest": "^27.0.3", - "@types/jsonwebtoken": "^8.5.6", "@types/lodash": "^4.14.178", "@types/luxon": "^2.0.8", "@types/node": "^16.11.3", @@ -2485,15 +2484,6 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "node_modules/@types/jsonwebtoken": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", - "integrity": "sha512-+P3O/xC7nzVizIi5VbF34YtqSonFsdnbXBnWUCYRiKOi1f9gA4sEFvXkrGr/QVV23IbMYvcoerI7nnhDUiWXRQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/lodash": { "version": "4.14.178", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", @@ -3268,11 +3258,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4155,14 +4140,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, "node_modules/electron-to-chromium": { "version": "1.4.18", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.18.tgz", @@ -7060,6 +7037,14 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jose": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.8.tgz", + "integrity": "sha512-EyUPtOKyTYq+iMOszO42eobQllaIjJnwkZ2U93aJzNyPibCy7CEvT9UQnaCVB51IAd49gbNdCew1c0LcLTCB2g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7258,21 +7243,6 @@ "node": "*" } }, - "node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", - "dependencies": { - "jws": "^3.2.2", - "lodash": "^4.17.21", - "ms": "^2.1.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, "node_modules/jsx-ast-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", @@ -7286,25 +7256,6 @@ "node": ">=4.0" } }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -7545,6 +7496,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -11995,6 +11947,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, "funding": [ { "type": "github", @@ -12449,6 +12402,7 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -13799,7 +13753,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yargs": { "version": "17.7.1", @@ -15771,15 +15726,6 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, - "@types/jsonwebtoken": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz", - "integrity": "sha512-+P3O/xC7nzVizIi5VbF34YtqSonFsdnbXBnWUCYRiKOi1f9gA4sEFvXkrGr/QVV23IbMYvcoerI7nnhDUiWXRQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/lodash": { "version": "4.14.178", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", @@ -16365,11 +16311,6 @@ "node-int64": "^0.4.0" } }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -17051,14 +16992,6 @@ } } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "electron-to-chromium": { "version": "1.4.18", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.18.tgz", @@ -19238,6 +19171,11 @@ } } }, + "jose": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.0.8.tgz", + "integrity": "sha512-EyUPtOKyTYq+iMOszO42eobQllaIjJnwkZ2U93aJzNyPibCy7CEvT9UQnaCVB51IAd49gbNdCew1c0LcLTCB2g==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -19391,17 +19329,6 @@ "through": ">=2.2.7 <3" } }, - "jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", - "requires": { - "jws": "^3.2.2", - "lodash": "^4.17.21", - "ms": "^2.1.1", - "semver": "^7.3.8" - } - }, "jsx-ast-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", @@ -19412,25 +19339,6 @@ "object.assign": "^4.1.2" } }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -19646,6 +19554,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -22758,7 +22667,8 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true }, "safe-regex": { "version": "2.1.1", @@ -23053,6 +22963,7 @@ "version": "7.3.8", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -24109,7 +24020,8 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "yargs": { "version": "17.7.1", diff --git a/package.json b/package.json index 39498ec3..6025d16a 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@grpc/grpc-js": "^1.6.12", "abort-controller-x": "^0.4.1", "axios": "^0.28.0", - "jsonwebtoken": "^9.0.0", + "jose": "^6.0.8", "lodash": "^4.17.21", "log4js": "^6.4.0", "long": "^5.2.0", @@ -41,7 +41,6 @@ "@commitlint/config-conventional": "^15.0.0", "@semantic-release/git": "^10.0.1", "@types/jest": "^27.0.3", - "@types/jsonwebtoken": "^8.5.6", "@types/lodash": "^4.14.178", "@types/luxon": "^2.0.8", "@types/node": "^16.11.3", diff --git a/src/token-service/iam-token-service.ts b/src/token-service/iam-token-service.ts index 06edef5d..8af467c7 100644 --- a/src/token-service/iam-token-service.ts +++ b/src/token-service/iam-token-service.ts @@ -1,7 +1,7 @@ import { credentials } from '@grpc/grpc-js'; -import * as jwt from 'jsonwebtoken'; import { DateTime } from 'luxon'; import { createChannel } from 'nice-grpc'; +import { importPKCS8, SignJWT } from 'jose'; import { cloudApi, serviceClients } from '..'; import { getServiceClientEndpoint } from '../service-endpoints'; import { IIAmCredentials, ISslCredentials, TokenService } from '../types'; @@ -48,21 +48,27 @@ export class IamTokenService implements TokenService { return clientFactory.create(IamTokenServiceClient.service, channel); } - private getJwtRequest() { + private cleanPrivateKey(key: Buffer | string): string { + const stringKey = Buffer.isBuffer(key) ? key.toString() : key; + + return stringKey.slice(stringKey.indexOf('-----BEGIN PRIVATE KEY-----')); + } + + private async getJwtRequest() { const now = DateTime.utc(); const expires = now.plus({ milliseconds: this.jwtExpirationTimeout }); - const payload = { - iss: this.iamCredentials.serviceAccountId, - aud: 'https://iam.api.cloud.yandex.net/iam/v1/tokens', - iat: Math.round(now.toSeconds()), - exp: Math.round(expires.toSeconds()), - }; - const options: jwt.SignOptions = { - algorithm: 'PS256', - keyid: this.iamCredentials.accessKeyId, - }; - - return jwt.sign(payload, this.iamCredentials.privateKey, options); + const alg = 'PS256'; + const privateKey = await importPKCS8(this.cleanPrivateKey(this.iamCredentials.privateKey), alg); + + const jwt = await new SignJWT() + .setProtectedHeader({ alg, kid: this.iamCredentials.accessKeyId, typ: 'JWT' }) + .setIssuer(this.iamCredentials.serviceAccountId) + .setAudience('https://iam.api.cloud.yandex.net/iam/v1/tokens') + .setIssuedAt(Math.round(now.toSeconds())) + .setExpirationTime(Math.round(expires.toSeconds())) + .sign(privateKey); + + return jwt; } private async initialize() { @@ -81,7 +87,7 @@ export class IamTokenService implements TokenService { return this.client().create( cloudApi.iam.iam_token_service.CreateIamTokenRequest.fromPartial({ - jwt: this.getJwtRequest(), + jwt: await this.getJwtRequest(), }), { deadline }, );