Skip to content

Commit

Permalink
Added new authorization_details parameter to support RAR requests
Browse files Browse the repository at this point in the history
  • Loading branch information
gyaneshgouraw-okta committed Apr 10, 2024
1 parent acdb96f commit 72f2230
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/auth/client-authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export const addClientAuthentication = async ({
clientSecret,
}: AddClientAuthenticationOptions): Promise<Record<string, unknown>> => {
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);
Expand Down
18 changes: 18 additions & 0 deletions src/auth/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<AuthorizationDetails>[];

/**
* Allow for any custom property to be sent to Auth0
*/
Expand Down
72 changes: 72 additions & 0 deletions test/auth/client-authentication.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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)
);
});
});

0 comments on commit 72f2230

Please sign in to comment.