From 9f90aee94fb86b2a365859fcaf99a06b004655ba Mon Sep 17 00:00:00 2001 From: JGiter Date: Fri, 10 Feb 2023 12:53:37 +0200 Subject: [PATCH] feat: get access tokens from cookies --- package-lock.json | 34 ++++++++- package.json | 2 + .../cache-client/cache-client.service.ts | 76 +++++++++++-------- 3 files changed, 79 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 25be3633..b999d2d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "iam-client-lib", - "version": "7.1.0-alpha.2", + "version": "7.1.0-alpha.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "iam-client-lib", - "version": "7.1.0-alpha.2", + "version": "7.1.0-alpha.3", "license": "GPL-3.0-or-later", "dependencies": { "@energyweb/credential-governance": "2.2.1-alpha.313.0", @@ -47,6 +47,7 @@ "nats.ws": "^1.7.1", "promise-retry": "^2.0.1", "qs": "^6.9.4", + "set-cookie-parser": "^2.5.1", "ts-interface-checker": "^1.0.2", "tslib": "^2.0.3", "uuid": "^7.0.3" @@ -71,6 +72,7 @@ "@types/lodash.difference": "^4.5.6", "@types/promise-retry": "^1.1.3", "@types/qs": "^6.9.5", + "@types/set-cookie-parser": "^2.4.2", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^5.9.1", "@typescript-eslint/parser": "^5.9.1", @@ -5623,6 +5625,15 @@ "@types/node": "*" } }, + "node_modules/@types/set-cookie-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", + "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/sjcl": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/@types/sjcl/-/sjcl-1.0.28.tgz", @@ -31661,6 +31672,11 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "node_modules/set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==" + }, "node_modules/set-delayed-interval": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/set-delayed-interval/-/set-delayed-interval-1.0.0.tgz", @@ -39683,6 +39699,15 @@ "@types/node": "*" } }, + "@types/set-cookie-parser": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", + "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/sjcl": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/@types/sjcl/-/sjcl-1.0.28.tgz", @@ -60179,6 +60204,11 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, + "set-cookie-parser": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz", + "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==" + }, "set-delayed-interval": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/set-delayed-interval/-/set-delayed-interval-1.0.0.tgz", diff --git a/package.json b/package.json index 41c41b70..6dc76bfd 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "nats.ws": "^1.7.1", "promise-retry": "^2.0.1", "qs": "^6.9.4", + "set-cookie-parser": "^2.5.1", "ts-interface-checker": "^1.0.2", "tslib": "^2.0.3", "uuid": "^7.0.3" @@ -126,6 +127,7 @@ "@types/lodash.difference": "^4.5.6", "@types/promise-retry": "^1.1.3", "@types/qs": "^6.9.5", + "@types/set-cookie-parser": "^2.4.2", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^5.9.1", "@typescript-eslint/parser": "^5.9.1", diff --git a/src/modules/cache-client/cache-client.service.ts b/src/modules/cache-client/cache-client.service.ts index 1a4b96da..e5f327ff 100644 --- a/src/modules/cache-client/cache-client.service.ts +++ b/src/modules/cache-client/cache-client.service.ts @@ -1,4 +1,4 @@ -import axios, { AxiosInstance } from 'axios'; +import axios, { AxiosInstance, AxiosResponse } from 'axios'; import { stringify } from 'qs'; import { IRoleDefinition } from '@energyweb/credential-governance'; import { IDIDDocument } from '@ew-did-registry/did-resolver-interface'; @@ -8,6 +8,7 @@ import { VerifiableCredential, } from '@ew-did-registry/credentials-interface'; import promiseRetry from 'promise-retry'; +import setCookie from 'set-cookie-parser'; import { IApp, IOrganization, IRole } from '../domains/domains.types'; import { AssetHistory } from '../assets/assets.types'; import { @@ -72,43 +73,26 @@ export class CacheClient implements ICacheClient { * After authentication runs previously failed requests */ async authenticate() { - let tokens: AuthTokens | undefined = undefined; - - const setTokens = () => { - if (!tokens) return; - if (!this.isBrowser) { - this._httpClient.defaults.headers.common[ - 'Authorization' - ] = `Bearer ${tokens.token}`; - } - this.refresh_token = tokens.refreshToken; - }; - // First try to refresh access token try { - const refreshedTokens = await this.refreshToken(); - tokens = refreshedTokens; - setTokens(); - - if (!tokens || !(await this.isAuthenticated())) { - tokens = undefined; - } + await this.refreshToken(); } catch { getLogger().warn('[CACHE CLIENT] failed to refresh tokens'); } // If refresh token failed or access token is not valid, then sign new identity token - if (!tokens) { + if (!(await this.isAuthenticated())) { getLogger().info('[CACHE CLIENT] obtaining new tokens'); delete this._httpClient.defaults.headers.common['Authorization']; const pubKeyAndIdentityToken = await this._signerService.publicKeyAndIdentityToken(true); - const { data } = await this._httpClient.post('/login', { + const res = await this._httpClient.post('/login', { identityToken: pubKeyAndIdentityToken.identityToken, }); + if (!this.isBrowser) { + this.setTokens(res); + } this.pubKeyAndIdentityToken = pubKeyAndIdentityToken; - tokens = data; - setTokens(); } getLogger().info('[CACHE CLIENT] authenticated'); } @@ -681,18 +665,48 @@ export class CacheClient implements ICacheClient { ); } - private async refreshToken(): Promise { - if (!this.refresh_token) return undefined; + private async refreshToken(): Promise { + if (!this.isBrowser && !this.refresh_token) return undefined; getLogger().info('[CACHE CLIENT] refreshing tokens'); - const { data } = await this._httpClient.get<{ - token: string; - refreshToken: string; - }>( + const res = await this._httpClient.get( `/refresh_token${ this.isBrowser ? '' : `?refresh_token=${this.refresh_token}` }` ); getLogger().debug('[CACHE CLIENT] refreshed tokens fetched'); - return data; + if (!this.isBrowser) { + this.setTokens(res); + } + } + + /** + * Saves access and refresh tokens + * + * @param res Response from login request + */ + private setTokens({ headers, data }: AxiosResponse) { + let token: AuthTokens['token'] | undefined; + let refreshToken: AuthTokens['refreshToken'] | undefined; + if (headers['set-cookie']) { + const cookies = setCookie.parse(headers['set-cookie'], { + decodeValues: false, + map: true, + }); + const tokenCookie = cookies['token']; + const refreshTokenCookie = cookies['refreshToken']; + + if (tokenCookie && refreshTokenCookie) { + token = tokenCookie.value; + refreshToken = refreshTokenCookie.value; + } + } + if (!token || !refreshToken) { + token = data.token; + refreshToken = data.refreshToken; + } + this.refresh_token = refreshToken; + this._httpClient.defaults.headers.common[ + 'Authorization' + ] = `Bearer ${token}`; } }