From 72f223033506a40cb4012e772bf58cf33f9b7dd9 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Wed, 10 Apr 2024 20:53:45 +0530 Subject: [PATCH 1/6] Added new authorization_details parameter to support RAR requests --- src/auth/client-authentication.ts | 3 ++ src/auth/oauth.ts | 18 +++++++ test/auth/client-authentication.test.ts | 72 +++++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/src/auth/client-authentication.ts b/src/auth/client-authentication.ts index 1c10fb9f0..ed93055d9 100644 --- a/src/auth/client-authentication.ts +++ b/src/auth/client-authentication.ts @@ -36,6 +36,9 @@ export const addClientAuthentication = async ({ clientSecret, }: AddClientAuthenticationOptions): Promise> => { const cid = payload.client_id || clientId; + if (payload.authorization_details) { + payload.authorization_details = JSON.stringify(payload.authorization_details); + } if (clientAssertionSigningKey && !payload.client_assertion) { const alg = clientAssertionSigningAlg || 'RS256'; const privateKey = await jose.importPKCS8(clientAssertionSigningKey, alg); diff --git a/src/auth/oauth.ts b/src/auth/oauth.ts index 736a0a1ac..29a89997d 100644 --- a/src/auth/oauth.ts +++ b/src/auth/oauth.ts @@ -91,6 +91,19 @@ export interface ClientCredentialsGrantRequest extends ClientCredentials { audience: string; } +interface AuthorizationDetails { + /** + * An identifier for the authorization details + */ + type: string; + + /** + * Allow for any custom property to be sent to Auth0 + * It represents data to specify the authorization requirements for a certain type of resource. + */ + [key: string]: any; +} + export interface PushedAuthorizationRequest extends ClientCredentials { /** * URI to redirect to. @@ -146,6 +159,11 @@ export interface PushedAuthorizationRequest extends ClientCredentials { */ code_challenge?: string; + /** + * Can carry fine-grained authorization data in OAuth messages as part of Rich Authorization Requests(RAR) {@link https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar | Reference} + */ + authorization_details?: Required[]; + /** * Allow for any custom property to be sent to Auth0 */ diff --git a/test/auth/client-authentication.test.ts b/test/auth/client-authentication.test.ts index 24d6583fd..7679fc98d 100644 --- a/test/auth/client-authentication.test.ts +++ b/test/auth/client-authentication.test.ts @@ -3,6 +3,7 @@ import { jest } from '@jest/globals'; import * as jose from 'jose'; import { AuthenticationClient } from '../../src/index.js'; import { TEST_PUBLIC_KEY, TEST_PRIVATE_KEY } from '../constants.js'; +import { addClientAuthentication } from '../../src/auth/client-authentication.js'; const URL = 'https://tenant.auth0.com/'; const clientId = 'test-client-id'; @@ -152,3 +153,74 @@ describe('client-authentication', () => { }); }); }); + +describe('client-authentication for par endpoint', () => { + const path = jest.fn(); + const body = jest.fn(); + const headers = jest.fn(); + const clientAssertion = jest.fn(); + + beforeEach(() => { + async function handler(this: any, pathIn: unknown, bodyIn: string) { + const bodyParsed = Object.fromEntries(new URLSearchParams(bodyIn)); + path(pathIn); + body(bodyParsed); + headers(this.req.headers); + if ((bodyParsed as any).client_assertion) { + clientAssertion(await verify(bodyParsed.client_assertion, TEST_PUBLIC_KEY, verifyOpts)); + } + return { + data: { + request_uri: 'https://www.request.uri', + expires_in: 86400, + }, + }; + } + + nock(URL, { encodedQueryParams: true }).post('/oauth/par').reply(200, handler).persist(); + }); + + afterEach(() => { + nock.cleanAll(); + jest.clearAllMocks(); + }); + + it('should allow you to call with cliendId & clientSecret combination', async () => { + const auth0 = new AuthenticationClient({ + domain: 'tenant.auth0.com', + clientId, + clientSecret: 'foo', + }); + await auth0.oauth.pushedAuthorization({ + client_id: 'test-client-id', + response_type: 'code', + redirect_uri: 'https://example.com', + }); + expect(path).toHaveBeenCalledWith('/oauth/par'); + + expect(body).toHaveBeenCalledWith({ + client_id: 'test-client-id', + client_secret: 'foo', + redirect_uri: 'https://example.com', + response_type: 'code', + }); + }); +}); + +describe('Validate addClientAuthentication function', () => { + it('should stringify authorization_details property of payload parameter', async () => { + const authorization_details = [{ type: 'payment_initiation', actions: ['write'] }]; + const authenticatedPayload = await addClientAuthentication({ + payload: { + authorization_details: authorization_details, + client_secret: 'foo', + }, + domain: 'tenant.auth0.com', + clientId, + }); + + expect(authenticatedPayload.authorization_details).toEqual( + JSON.stringify(authorization_details) + ); + }); +}); From 7442f4cd6e8a71546abde59873d2a0235959bf09 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Mon, 15 Apr 2024 10:19:13 +0530 Subject: [PATCH 2/6] Updated changes for new authorization_details parameter RAR requests --- src/auth/client-authentication.ts | 3 --- src/auth/oauth.ts | 17 ++--------------- test/auth/client-authentication.test.ts | 18 ------------------ 3 files changed, 2 insertions(+), 36 deletions(-) diff --git a/src/auth/client-authentication.ts b/src/auth/client-authentication.ts index ed93055d9..1c10fb9f0 100644 --- a/src/auth/client-authentication.ts +++ b/src/auth/client-authentication.ts @@ -36,9 +36,6 @@ export const addClientAuthentication = async ({ clientSecret, }: AddClientAuthenticationOptions): Promise> => { const cid = payload.client_id || clientId; - if (payload.authorization_details) { - payload.authorization_details = JSON.stringify(payload.authorization_details); - } if (clientAssertionSigningKey && !payload.client_assertion) { const alg = clientAssertionSigningAlg || 'RS256'; const privateKey = await jose.importPKCS8(clientAssertionSigningKey, alg); diff --git a/src/auth/oauth.ts b/src/auth/oauth.ts index 29a89997d..7b8751815 100644 --- a/src/auth/oauth.ts +++ b/src/auth/oauth.ts @@ -91,19 +91,6 @@ export interface ClientCredentialsGrantRequest extends ClientCredentials { audience: string; } -interface AuthorizationDetails { - /** - * An identifier for the authorization details - */ - type: string; - - /** - * Allow for any custom property to be sent to Auth0 - * It represents data to specify the authorization requirements for a certain type of resource. - */ - [key: string]: any; -} - export interface PushedAuthorizationRequest extends ClientCredentials { /** * URI to redirect to. @@ -160,9 +147,9 @@ export interface PushedAuthorizationRequest extends ClientCredentials { code_challenge?: string; /** - * Can carry fine-grained authorization data in OAuth messages as part of Rich Authorization Requests(RAR) {@link https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar | Reference} + * A JSON stringified an array of objects. It Can carry fine-grained authorization data in OAuth messages as part of Rich Authorization Requests(RAR) {@link https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar | Reference} */ - authorization_details?: Required[]; + authorization_details?: string; /** * Allow for any custom property to be sent to Auth0 diff --git a/test/auth/client-authentication.test.ts b/test/auth/client-authentication.test.ts index 7679fc98d..2ba46c2e6 100644 --- a/test/auth/client-authentication.test.ts +++ b/test/auth/client-authentication.test.ts @@ -206,21 +206,3 @@ describe('client-authentication for par endpoint', () => { }); }); }); - -describe('Validate addClientAuthentication function', () => { - it('should stringify authorization_details property of payload parameter', async () => { - const authorization_details = [{ type: 'payment_initiation', actions: ['write'] }]; - const authenticatedPayload = await addClientAuthentication({ - payload: { - authorization_details: authorization_details, - client_secret: 'foo', - }, - domain: 'tenant.auth0.com', - clientId, - }); - - expect(authenticatedPayload.authorization_details).toEqual( - JSON.stringify(authorization_details) - ); - }); -}); From 38eabec87d87dbc28f8cf1dfb16def0cc7cb53de Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Mon, 15 Apr 2024 10:28:18 +0530 Subject: [PATCH 3/6] Removed unused import addClientAuthentication --- test/auth/client-authentication.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/auth/client-authentication.test.ts b/test/auth/client-authentication.test.ts index 2ba46c2e6..53000d469 100644 --- a/test/auth/client-authentication.test.ts +++ b/test/auth/client-authentication.test.ts @@ -3,7 +3,6 @@ import { jest } from '@jest/globals'; import * as jose from 'jose'; import { AuthenticationClient } from '../../src/index.js'; import { TEST_PUBLIC_KEY, TEST_PRIVATE_KEY } from '../constants.js'; -import { addClientAuthentication } from '../../src/auth/client-authentication.js'; const URL = 'https://tenant.auth0.com/'; const clientId = 'test-client-id'; From 1a9585e50b8d2bda345855a9b1cac1c998259747 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Mon, 15 Apr 2024 13:13:24 +0530 Subject: [PATCH 4/6] Updated description of authorization_details parameter as suggested in review comments --- src/auth/oauth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth/oauth.ts b/src/auth/oauth.ts index 7b8751815..459881415 100644 --- a/src/auth/oauth.ts +++ b/src/auth/oauth.ts @@ -147,7 +147,7 @@ export interface PushedAuthorizationRequest extends ClientCredentials { code_challenge?: string; /** - * A JSON stringified an array of objects. It Can carry fine-grained authorization data in OAuth messages as part of Rich Authorization Requests(RAR) {@link https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar | Reference} + * A JSON stringified array of objects. It can carry fine-grained authorization data in OAuth messages as part of Rich Authorization Requests (RAR) {@link https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar | Reference} */ authorization_details?: string; From a185a4850bc367e8f8587f7d22c16ceb470ad987 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Mon, 15 Apr 2024 14:20:10 +0530 Subject: [PATCH 5/6] Added unit test for RAR changes --- test/auth/oauth.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/auth/oauth.test.ts b/test/auth/oauth.test.ts index ec61fc9f3..052d809d8 100644 --- a/test/auth/oauth.test.ts +++ b/test/auth/oauth.test.ts @@ -328,6 +328,25 @@ describe('OAuth', () => { }, }); }); + + it('should send authorization_details when provided', async () => { + const oauth = new OAuth(opts); + await expect( + oauth.pushedAuthorization({ + client_id: 'test-client-id', + response_type: 'code', + redirect_uri: 'https://example.com', + authorization_details: JSON.stringify([ + { type: 'payment_initiation', actions: ['write'] }, + ]), + }) + ).resolves.toMatchObject({ + data: { + request_uri: 'https://www.request.uri', + expires_in: 86400, + }, + }); + }); }); }); From f4f5c739b5af4b3c3b249dd3801b076327712bc1 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Mon, 15 Apr 2024 15:14:51 +0530 Subject: [PATCH 6/6] Added mock api response in /par response wrt. authorization_details parameter --- test/auth/fixtures/oauth.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/auth/fixtures/oauth.json b/test/auth/fixtures/oauth.json index 0c8e4ac6f..4489dd04f 100644 --- a/test/auth/fixtures/oauth.json +++ b/test/auth/fixtures/oauth.json @@ -167,5 +167,16 @@ "request_uri": "https://www.request.uri", "expires_in": 86400 } + }, + { + "scope": "https://test-domain.auth0.com", + "method": "POST", + "path": "/oauth/par", + "body": "client_id=test-client-id&response_type=code&redirect_uri=https%3A%2F%2Fexample.com&authorization_details=%5B%7B%22type%22%3A%22payment_initiation%22%2C%22actions%22%3A%5B%22write%22%5D%7D%5D&client_secret=test-client-secret", + "status": 200, + "response": { + "request_uri": "https://www.request.uri", + "expires_in": 86400 + } } ]