diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8164531 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node-terminal", + "request": "launch", + "name": "Debug tests", + "skipFiles": [ + "/**" + ], + "command": "npm test" + } + ] +} diff --git a/src/serviceClientTokenProvider.js b/src/serviceClientTokenProvider.js index 1aafcfc..aad10dc 100644 --- a/src/serviceClientTokenProvider.js +++ b/src/serviceClientTokenProvider.js @@ -26,7 +26,7 @@ class ServiceClientTokenProvider { } // 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 useAuthressCustomDomain = this.authressCustomDomain && !this.authressCustomDomain.match(/authress\.io/); + const useAuthressCustomDomain = this.authressCustomDomain && !this.authressCustomDomain.match(/\.api-[a-z0-9-]+\.authress\.io/); const now = Math.round(Date.now() / 1000); const jwt = Object.assign({ diff --git a/src/tokenVerifier.js b/src/tokenVerifier.js index 7053c90..9c9219e 100644 --- a/src/tokenVerifier.js +++ b/src/tokenVerifier.js @@ -93,14 +93,15 @@ module.exports = async function(authressCustomDomainOrHttpClient, requestToken, throw new TokenVerificationError('Unauthorized: No Issuer found'); } - const completeIssuerUrl = new URL(getSanitizedIssuerUrl(authressCustomDomain)); - const altIssuerUrl = new URL(sanitizeUrl(authressCustomDomain)); + const completeIssuerUrlOrigin = new URL(getSanitizedIssuerUrl(authressCustomDomain)).origin; + const altIssuerUrlOrigin = new URL(sanitizeUrl(authressCustomDomain)).origin; + const altGlobalIssuerUrlOrigin = new URL(sanitizeUrl(authressCustomDomain)).origin.replace(/^https:\/\/([a-z0-9-]+)[.][a-z0-9-]+[.]authress[.]io$/, 'https://$1.api.authress.io'); try { - if (new URL(issuer).origin !== completeIssuerUrl.origin && new URL(issuer).origin !== altIssuerUrl.origin) { - throw new TokenVerificationError(`Unauthorized: Invalid Issuer: ${issuer}`); + if (new URL(issuer).origin !== completeIssuerUrlOrigin && new URL(issuer).origin !== altIssuerUrlOrigin && new URL(issuer).origin !== altGlobalIssuerUrlOrigin) { + throw new TokenVerificationError(`Unauthorized: Invalid Issuer: ${issuer}, Expected: ${completeIssuerUrlOrigin}`); } } catch (error) { - throw new TokenVerificationError(`Unauthorized: Invalid Issuer: ${issuer}`); + throw new TokenVerificationError(`Unauthorized: Invalid Issuer: ${issuer}, Expected: ${completeIssuerUrlOrigin}`); } // Handle service client checking diff --git a/tests/tokenVerifier.test.js b/tests/tokenVerifier.test.js index d447cf6..0d0e1d1 100644 --- a/tests/tokenVerifier.test.js +++ b/tests/tokenVerifier.test.js @@ -15,33 +15,60 @@ describe('tokenVerifier.js', () => { it('Validate RS512 token works', async () => { const userToken = 'eyJhbGciOiJSUzUxMiIsInR5cCI6ImF0K2p3dCIsImtpZCI6IjhDVGJSVGlYMVFUcnU0QmhwYnVoNFcifQ.eyJpc3MiOiJodHRwczovL2xvZ2luLmF1dGhyZXNzLmlvIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMDk1MzY2Mjc4NDQ3MjIzOTc5MTEiLCJpYXQiOjE2MzYyMDAyMjcsImV4cCI6MTYzNjI4NjYyNywic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsImF6cCI6Imdvb2dsZSIsImNsaWVudF9pZCI6IkFVVEhSRVNTIiwiYXVkIjpbImh0dHBzOi8vYXBpLmF1dGhyZXNzLmlvIl19.H26E36M5aBKqJ2IOfHtnmuaJe-2p_yWnePF55IIBpgl8BKXJAWtkHfXPnUYilb3ZyNe_5xg9Oo6VRhPs2Wp8s6OoR7Qr8JGGaMZVnVxrM83xf6JtD7q55TgA40QZrySHAMV7pmGLMCc8MqNXrYSwGsL-q4KgIC0_GyPMFHO090_EK5BUIhdYcDojAiOt8JSQ8d-u8arIO3grNkbaSLoa1Ge3Ebx1_JhQwEK-73zCTgvSdKkgYTMZCJctdR8VaeUpmapHFT78JHbG0c6VAShqwpC2aexeql-yk21m7Tb9i3ge4oJBxlqoPuwEtV5WjxlNgLb3lyW2owJnA6NijpPwNg'; await TokenVerifier('https://login.authress.io', userToken, { verifierOptions: { currentDate: new Date('2021-11-07') } }); - }).timeout(10000); + }); it('Validate EdDSA service client token', async () => { - const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.a43706ca-9647-40e4-aeae-7dcaa54bbab3.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; + const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.ignore-account-id.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; const publicKey = { alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519', x: 'JxtSC5tZZJuaW7Aeu5Kh_3tgCpPZRkHaaFyTj5sQ3KU' }; const tokenProvider = new ServiceClientTokenProvider(accessKey, customDomain); const initialToken = await tokenProvider.getToken(); await TokenVerifier(`https://${customDomain}`, initialToken, { expectedPublicKey: publicKey, verifierOptions: { currentDate: new Date('2022-05-07') } }); - }).timeout(10000); + }); it('Ensure incorrect domain specification for issuer still works', async () => { - const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.a43706ca-9647-40e4-aeae-7dcaa54bbab3.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; + const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.acc0-authress-account-id.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; + const publicKey = { alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519', x: 'JxtSC5tZZJuaW7Aeu5Kh_3tgCpPZRkHaaFyTj5sQ3KU' }; + const tokenProvider = new ServiceClientTokenProvider(accessKey, 'acc0-authress-account-id.login.authress.io'); + const initialToken = await tokenProvider.getToken(); + + await TokenVerifier('acc0-authress-account-id.api.authress.io', initialToken, { expectedPublicKey: publicKey, verifierOptions: { currentDate: new Date('2022-05-07') } }); + }); + + it('Missing domain specification for issuer still works.', async () => { + const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.acc0-authress-account-id.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; + const publicKey = { alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519', x: 'JxtSC5tZZJuaW7Aeu5Kh_3tgCpPZRkHaaFyTj5sQ3KU' }; + const tokenProvider = new ServiceClientTokenProvider(accessKey); + const initialToken = await tokenProvider.getToken(); + + await TokenVerifier('acc0-authress-account-id.api.authress.io', initialToken, { expectedPublicKey: publicKey, verifierOptions: { currentDate: new Date('2022-05-07') } }); + }); + + it('Missing domain specification for issuer still works if both are incorrectly set', async () => { + const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.acc0-authress-account-id.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; + const publicKey = { alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519', x: 'JxtSC5tZZJuaW7Aeu5Kh_3tgCpPZRkHaaFyTj5sQ3KU' }; + const tokenProvider = new ServiceClientTokenProvider(accessKey); + const initialToken = await tokenProvider.getToken(); + + await TokenVerifier('acc0-authress-account-id.api-eu-west.authress.io', initialToken, { expectedPublicKey: publicKey, verifierOptions: { currentDate: new Date('2022-05-07') } }); + }); + + it('Ensure incorrect domain specification for issuer still works', async () => { + const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.account.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; const publicKey = { alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519', x: 'JxtSC5tZZJuaW7Aeu5Kh_3tgCpPZRkHaaFyTj5sQ3KU' }; const tokenProvider = new ServiceClientTokenProvider(accessKey, 'account.login.authress.io'); const initialToken = await tokenProvider.getToken(); await TokenVerifier('account.api-eu-west.authress.io', initialToken, { expectedPublicKey: publicKey, verifierOptions: { currentDate: new Date('2022-05-07') } }); - }).timeout(10000); + }); it('Ensure incorrect domain specification for issuer still works if both are incorrectly set', async () => { - const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.a43706ca-9647-40e4-aeae-7dcaa54bbab3.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; + const accessKey = 'sc_aAKceYi7VJDCU8vB7HcTo3Q.pogP.account.MC4CAQAwBQYDK2VwBCIEIDVjjrIVCH3dVRq4ixRzBwjVHSoB2QzZ2iJuHq1Wshwp'; const publicKey = { alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519', x: 'JxtSC5tZZJuaW7Aeu5Kh_3tgCpPZRkHaaFyTj5sQ3KU' }; const tokenProvider = new ServiceClientTokenProvider(accessKey, 'account.api-eu-west.authress.io'); const initialToken = await tokenProvider.getToken(); await TokenVerifier('account.api-eu-west.authress.io', initialToken, { expectedPublicKey: publicKey, verifierOptions: { currentDate: new Date('2022-05-07') } }); - }).timeout(10000); + }); }); -}); +}); \ No newline at end of file