Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed missing endpoints for feature Organizations for Client Credentials changes #1046

Merged
merged 6 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,3 @@ jobs:
- name: Tests
shell: bash
run: npm run test:ci

- name: Upload coverage
if: matrix.node-version == '18.17'
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # [email protected]
with:
token: ${{ secrets.CODECOV_TOKEN }}

12 changes: 0 additions & 12 deletions src/auth/id-token-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,24 +102,12 @@ export class IDTokenValidator {
'Organization Id (org_id) claim must be a string present in the ID token'
);
}

if (payload.org_id !== organization) {
throw new Error(
`Organization Id (org_id) claim value mismatch in the ID token; expected "${organization}", found "${payload.org_id}"'`
);
}
} else {
if (!payload.org_name || typeof payload.org_name !== 'string') {
throw new Error(
'Organization Name (org_name) claim must be a string present in the ID token'
);
}

if (payload.org_name !== organization.toLowerCase()) {
throw new Error(
`Organization Name (org_name) claim value mismatch in the ID token; expected "${organization}", found "${payload.org_name}"'`
);
}
}
}

Expand Down
61 changes: 60 additions & 1 deletion src/management/__generated/managers/organizations-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
GetInvitations200ResponseOneOfInner,
GetMembers200Response,
GetOrganizationClientGrants200Response,
GetOrganizationClientGrants200ResponseOneOfInner,
GetOrganizationMemberRoles200Response,
GetOrganizations200Response,
GetOrganizations200ResponseOneOfInner,
Expand All @@ -17,6 +18,7 @@ import type {
PostEnabledConnectionsRequest,
PostInvitationsRequest,
PostMembersRequest,
PostOrganizationClientGrantsRequest,
PostOrganizationMemberRolesRequest,
PostOrganizations201Response,
PostOrganizationsRequest,
Expand All @@ -25,10 +27,10 @@ import type {
GetMembers200ResponseOneOf,
GetMembers200ResponseOneOfInner,
GetOrganizationClientGrants200ResponseOneOf,
GetOrganizationClientGrants200ResponseOneOfInner,
GetOrganizationMemberRoles200ResponseOneOf,
GetOrganizationMemberRoles200ResponseOneOfInner,
GetOrganizations200ResponseOneOf,
DeleteClientGrantsByGrantIdRequest,
DeleteEnabledConnectionsByConnectionIdRequest,
DeleteInvitationsByInvitationIdRequest,
DeleteMembersOperationRequest,
Expand All @@ -49,6 +51,7 @@ import type {
PostEnabledConnectionsOperationRequest,
PostInvitationsOperationRequest,
PostMembersOperationRequest,
PostOrganizationClientGrantsOperationRequest,
PostOrganizationMemberRolesOperationRequest,
} from '../models/index.js';

Expand All @@ -58,6 +61,30 @@ const { BaseAPI } = runtime;
*
*/
export class OrganizationsManager extends BaseAPI {
/**
* Remove a client grant from an organization
*
* @throws {RequiredError}
*/
async deleteClientGrantsByGrantId(
requestParameters: DeleteClientGrantsByGrantIdRequest,
initOverrides?: InitOverride
): Promise<ApiResponse<void>> {
runtime.validateRequiredRequestParams(requestParameters, ['id', 'grant_id']);

const response = await this.request(
{
path: `/organizations/{id}/client-grants/{grant_id}`
.replace('{id}', encodeURIComponent(String(requestParameters.id)))
.replace('{grant_id}', encodeURIComponent(String(requestParameters.grant_id))),
method: 'DELETE',
},
initOverrides
);

return runtime.VoidApiResponse.fromResponse(response);
}

/**
* Delete connections from an organization
*
Expand Down Expand Up @@ -859,6 +886,38 @@ export class OrganizationsManager extends BaseAPI {
return runtime.VoidApiResponse.fromResponse(response);
}

/**
* Associate a client grant with an organization
*
* @throws {RequiredError}
*/
async postOrganizationClientGrants(
requestParameters: PostOrganizationClientGrantsOperationRequest,
bodyParameters: PostOrganizationClientGrantsRequest,
initOverrides?: InitOverride
): Promise<ApiResponse<GetOrganizationClientGrants200ResponseOneOfInner>> {
runtime.validateRequiredRequestParams(requestParameters, ['id']);

const headerParameters: runtime.HTTPHeaders = {};

headerParameters['Content-Type'] = 'application/json';

const response = await this.request(
{
path: `/organizations/{id}/client-grants`.replace(
'{id}',
encodeURIComponent(String(requestParameters.id))
),
method: 'POST',
headers: headerParameters,
body: bodyParameters,
},
initOverrides
);

return runtime.JSONApiResponse.fromResponse(response);
}

/**
* Assign one or more roles to a given user that will be applied in the context of the provided organization
*
Expand Down
35 changes: 35 additions & 0 deletions src/management/__generated/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10513,6 +10513,16 @@
*/
members: Array<string>;
}
/**
*
*/
export interface PostOrganizationClientGrantsRequest {
/**
* A Client Grant ID to add to the organization.
*
*/
grant_id: string;
}
/**
*
*/
Expand Down Expand Up @@ -12146,7 +12156,7 @@
/**
*
*/
export interface SsProfileList extends Array<SsProfile> {}

Check warning on line 12159 in src/management/__generated/models/index.ts

View workflow job for this annotation

GitHub Actions / Build and Test (18.17)

An interface declaring no members is equivalent to its supertype

Check warning on line 12159 in src/management/__generated/models/index.ts

View workflow job for this annotation

GitHub Actions / Build and Test (20.3)

An interface declaring no members is equivalent to its supertype
/**
*
*/
Expand Down Expand Up @@ -14924,6 +14934,21 @@
*/
id: string;
}
/**
*
*/
export interface DeleteClientGrantsByGrantIdRequest {
/**
* Organization identifier
*
*/
id: string;
/**
* The Client Grant ID to remove from the organization
*
*/
grant_id: string;
}
/**
*
*/
Expand Down Expand Up @@ -15319,6 +15344,16 @@
*/
id: string;
}
/**
*
*/
export interface PostOrganizationClientGrantsOperationRequest {
/**
* Organization identifier
*
*/
id: string;
}
/**
*
*/
Expand Down
56 changes: 0 additions & 56 deletions test/auth/id-token-validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,60 +386,4 @@ describe('id-token-validator', () => {
'Organization Name (org_name) claim must be a string present in the ID token'
);
});

it('should throw when org id claim doesnt match org expected', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_id: 'org_1234' } });

await expect(idTokenValidator.validate(jwt, { organization: 'org_123' })).rejects.toThrow(
'Organization Id (org_id) claim value mismatch in the ID token; expected "org_123", found "org_1234'
);
});

it('should throw when org name claim doesnt match org expected', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_name: 'notExpectedOrg' } });

await expect(idTokenValidator.validate(jwt, { organization: 'testorg' })).rejects.toThrow(
'Organization Name (org_name) claim value mismatch in the ID token; expected "testorg", found "notExpectedOrg'
);
});

it('should NOT throw when org_id matches expected organization', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_id: 'org_123' } });

await expect(
idTokenValidator.validate(jwt, { organization: 'org_123' })
).resolves.not.toThrow();
});

it('should NOT throw when org_name matches expected organization', async () => {
const idTokenValidator = new IDTokenValidator({
domain: DOMAIN,
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
});

const jwt = await sign({ payload: { org_name: 'testorg' } });

await expect(
idTokenValidator.validate(jwt, { organization: 'testOrg' })
).resolves.not.toThrow();
});
});
34 changes: 0 additions & 34 deletions test/auth/oauth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,38 +409,4 @@ describe('OAuth (with ID Token validation)', () => {
);
nockDone();
});

it('should throw for invalid organization id', async () => {
const { nockDone } = await nockBack('auth/fixtures/oauth.json', {
before: await withIdToken({
...opts,
payload: { org_id: 'org_123' },
}),
});
const oauth = new OAuth(opts);
await expect(
oauth.refreshTokenGrant(
{ refresh_token: 'test-refresh-token' },
{ idTokenValidateOptions: { organization: 'org_1235' } }
)
).rejects.toThrowError(/\(org_id\) claim value mismatch in the ID token/);
nockDone();
});

it('should throw for invalid organization name', async () => {
const { nockDone } = await nockBack('auth/fixtures/oauth.json', {
before: await withIdToken({
...opts,
payload: { org_name: 'org123' },
}),
});
const oauth = new OAuth(opts);
await expect(
oauth.refreshTokenGrant(
{ refresh_token: 'test-refresh-token' },
{ idTokenValidateOptions: { organization: 'org1235' } }
)
).rejects.toThrowError(/\(org_name\) claim value mismatch in the ID token/);
nockDone();
});
});
47 changes: 39 additions & 8 deletions test/management/organizations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ import {
GetOrganizationClientGrantsRequest,
GetOrganizationClientGrants200Response,
ApiResponse,
DeleteClientGrantsByGrantIdRequest,
GetOrganizationClientGrants200ResponseOneOfInner,
} from '../../src/index.js';

describe('OrganizationsManager', () => {
let organizations: OrganizationsManager;
import { checkMethod } from '../utils/index.js';

describe('OrganizationsManager', () => {
let request: nock.Scope;
const token = 'TOKEN';

beforeAll(() => {
const client = new ManagementClient({
domain: 'tenant.auth0.com',
token: token,
});
organizations = client.organizations;
const client = new ManagementClient({
domain: 'tenant.auth0.com',
token: token,
});
const organizations: OrganizationsManager = client.organizations;

describe('#constructor', () => {
it('should throw an error when no base URL is provided', () => {
Expand Down Expand Up @@ -1474,4 +1474,35 @@ describe('OrganizationsManager', () => {
});
});
});

describe('#deleteClientGrantsById', () => {
const requestParameters: DeleteClientGrantsByGrantIdRequest = {
id: 'org_123',
grant_id: 'grant_id',
};
const operation = organizations.deleteClientGrantsByGrantId(requestParameters);
const expectedResponse = undefined;
const uri = `/organizations/{id}/client-grants/{grant_id}`
.replace('{id}', encodeURIComponent(String(requestParameters.id)))
.replace('{grant_id}', encodeURIComponent(String(requestParameters.grant_id)));
const method = 'delete';

checkMethod({ operation, expectedResponse, uri, method });
});

describe('#postOrganizationClientGrants', () => {
const requestParameters = { id: 'org_123' };
const requestBody = { grant_id: 'grant_id' };
const operation = organizations.postOrganizationClientGrants(requestParameters, requestBody);
const expectedResponse: GetOrganizationClientGrants200ResponseOneOfInner = <
GetOrganizationClientGrants200ResponseOneOfInner
>{};
const uri = `/organizations/{id}/client-grants`.replace(
'{id}',
encodeURIComponent(String(requestParameters.id))
);
const method = 'post';

checkMethod({ operation, expectedResponse, uri, method, requestBody });
});
});
1 change: 1 addition & 0 deletions test/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './extractParts.js';
export * from './withIdToken.js';
export * from './wrapperTestUtils.js';
Loading
Loading