From d951f0da00f3f4dd681e6e3456aff917269fde5f Mon Sep 17 00:00:00 2001 From: Warren Parad Date: Wed, 1 Mar 2023 14:26:02 +0100 Subject: [PATCH] Pass custom domain into the service client token generation. --- CHANGELOG.md | 1 + index.d.ts | 2 +- index.js | 2 +- src/httpClient.js | 2 +- src/serviceClientTokenProvider.js | 8 ++++++-- tests/serviceClientTokenProvider.test.js | 4 ++-- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a2ffcb..4c6f395 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This is the changelog for [Authress SDK](readme.md). * Enable passing just the access token as a string to `AuthressClient`. * Fix the issuer path for service client tokens to include the accountId when the custom domain is not specified. The default issuer is converted from `api.authress.io` to `accountId.api.authress.io`. if this fallback issuer domain was specified in your authorizer, upgrading this library without changing your defined issuer, which prevent future access. * Add automatic retries to all requests. +* Fix service client token generated tokens so that they automatically get the custom domain injected in during using in the SDK. ## 1.3 ## * Add new `Pagination` type which pagination `next.cursor` to enable paging through resources. diff --git a/index.d.ts b/index.d.ts index 1814aba..fa15df1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1368,7 +1368,7 @@ export class ServiceClientTokenProvider { * Generate the url to redirect the user back to your application from your authentication server after their credentials have been successfully verified. All these parameters should be found passed through from the user's login attempt along with their credentials. The authentication server receives a request from the user to login, with these values. Then these are constructed and sent back to Authress to verify the generated login data. * @summary Generate the url to redirect the user back to your application from your authentication server after their credentials have been successfully verified. * @type {Function>} - * @param {string} authressCustomDomainLoginUrl The url sent with the request for the user to login, this should match the Authress custom domain: https://authress.io/app/#/setup?focus=domain and end in /login for example https://login.domain.com/login. This value is sent as the `redirect_uri` query string parameter in the request for simplicity. + * @param {string} authressCustomDomainLoginUrl The url sent with the request for the user to login, this should match the Authress custom domain: https://authress.io/app/#/setup?focus=domain and end in /login for example https://login.domain.com/login. This value is sent as the `redirect_uri` query string parameter in the request and should be passed directly into the SDK for simplicity. Avoid trying to manually construct this url. * @param {string} state The state parameter sent to the authentication server. * @param {string} clientId The clientId parameter sent to the authentication server. This will be validated against the client's credentials specified in the {@link ServiceClientTokenProvider} * @param {string} userId The user to request a JWT for. diff --git a/index.js b/index.js index 2ab9a0d..b5d4e92 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ const ServiceClientTokenProvider = require('./src/serviceClientTokenProvider'); class AuthressClient { constructor(settings, tokenProvider) { this.settings = settings || {}; - this.tokenProvider = (tokenProvider && typeof tokenProvider === 'string') ? new ServiceClientTokenProvider(tokenProvider) : tokenProvider; + this.tokenProvider = typeof tokenProvider === 'string' ? new ServiceClientTokenProvider(tokenProvider, this.settings.baseUrl) : tokenProvider; this.httpClient = new httpClient(this.settings.baseUrl, this.tokenProvider); this.accessRecords = new AccessRecordsApi(this.httpClient); diff --git a/src/httpClient.js b/src/httpClient.js index 22d2423..dce15a1 100644 --- a/src/httpClient.js +++ b/src/httpClient.js @@ -32,7 +32,7 @@ class HttpClient { const client = axios.create({ baseURL: this.baseUrl }); client.interceptors.request.use(async config => { - const token = await (typeof this.tokenProvider === 'function' ? this.tokenProvider() : this.tokenProvider.getToken()); + const token = await (typeof this.tokenProvider === 'function' ? this.tokenProvider(this.baseUrl) : this.tokenProvider.getToken(this.baseUrl)); config.headers = { ...config.headers, Authorization: `Bearer ${token}` diff --git a/src/serviceClientTokenProvider.js b/src/serviceClientTokenProvider.js index 6215d94..3bdfdae 100644 --- a/src/serviceClientTokenProvider.js +++ b/src/serviceClientTokenProvider.js @@ -14,15 +14,19 @@ module.exports = function(accessKey, authressCustomDomain) { audience: `${accountId}.accounts.authress.io`, privateKey: accessKey.split('.')[3] }; - const innerGetToken = async () => { + // Injects the custom domain in case the original service provider wasn't specified with it initially + const innerGetToken = async fallbackAuthressCustomDomain => { if (this.cachedKeyData && this.cachedKeyData.token && this.cachedKeyData.expires > Date.now() + 3600000) { return this.cachedKeyData.token; } + // Do not set the issuer to be ${accountId}.api-region.authress.io it should always be set as the authress custom domain, the custom domain, or the generic api.authress.io one + const useFallbackAuthressCustomDomain = fallbackAuthressCustomDomain && !fallbackAuthressCustomDomain.match(/authress\.io/); + const now = Math.round(Date.now() / 1000); const jwt = { aud: decodedAccessKey.audience, - iss: getIssuer(authressCustomDomain || `${accountId}.api.authress.io`, decodedAccessKey), + iss: getIssuer(authressCustomDomain || useFallbackAuthressCustomDomain && fallbackAuthressCustomDomain || `${accountId}.api.authress.io`, decodedAccessKey), sub: decodedAccessKey.clientId, iat: now, // valid for 24 hours diff --git a/tests/serviceClientTokenProvider.test.js b/tests/serviceClientTokenProvider.test.js index 19df80b..b35f9c5 100644 --- a/tests/serviceClientTokenProvider.test.js +++ b/tests/serviceClientTokenProvider.test.js @@ -9,7 +9,7 @@ beforeEach(() => { sandbox = sinon.createSandbox(); }); afterEach(() => sandbox.restore()); describe('serviceClientTokenProvider.js', () => { - describe('getToken', () => { + describe('tokenProvider as a function itself', () => { it('Validate cache tokens work', async () => { const accessKey = 'SC|uEsXtFNjUbf1LEgAGeUhC3.uDeF.a43706ca-9647-40e4-aeae-7dcaa54bbab3.MC4CAQAwBQYDK2VwBCIEIE99LFw2c3DCiYwrY/Qkg1nIDiagoHtdCwb88RxarVYA'; const tokenProvider = new ServiceClientTokenProvider(accessKey); @@ -19,7 +19,7 @@ describe('serviceClientTokenProvider.js', () => { }); }); - describe('getToken() function', () => { + describe('getToken() function property', () => { it('Validate cache tokens work', async () => { const accessKey = 'SC|uEsXtFNjUbf1LEgAGeUhC3.uDeF.a43706ca-9647-40e4-aeae-7dcaa54bbab3.MC4CAQAwBQYDK2VwBCIEIE99LFw2c3DCiYwrY/Qkg1nIDiagoHtdCwb88RxarVYA'; const tokenProvider = new ServiceClientTokenProvider(accessKey);