Skip to content

Commit 1daaf95

Browse files
committed
chore: cherry-pick machine auth verification methods rename and API keys hook fix
1 parent 1dd405b commit 1daaf95

File tree

10 files changed

+86
-15
lines changed

10 files changed

+86
-15
lines changed

integration/tests/machine-auth/component.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,43 @@ testAgainstRunningApps({
285285
await u.page.unrouteAll();
286286
});
287287

288+
test('UserProfile API keys uses user ID as subject even when organization is active', async ({ page, context }) => {
289+
const u = createTestUtils({ app, page, context });
290+
291+
const admin = await u.services.users.getUser({ email: fakeAdmin.email });
292+
expect(admin).toBeDefined();
293+
const userId = admin.id;
294+
295+
await u.po.signIn.goTo();
296+
await u.po.signIn.waitForMounted();
297+
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeAdmin.email, password: fakeAdmin.password });
298+
await u.po.expect.toBeSignedIn();
299+
300+
await u.po.organizationSwitcher.goTo();
301+
await u.po.organizationSwitcher.waitForMounted();
302+
await u.po.organizationSwitcher.waitForAnOrganizationToSelected();
303+
304+
let capturedSubject: string | null = null;
305+
const apiKeyRequestPromise = u.page.waitForRequest(request => {
306+
if (request.url().includes('api_keys')) {
307+
const url = new URL(request.url());
308+
capturedSubject = url.searchParams.get('subject');
309+
return true;
310+
}
311+
return false;
312+
});
313+
314+
await u.po.page.goToRelative('/user');
315+
await u.po.userProfile.waitForMounted();
316+
await u.po.userProfile.switchToAPIKeysTab();
317+
318+
await apiKeyRequestPromise;
319+
320+
// Verify the subject parameter is the user ID, not the organization ID
321+
expect(capturedSubject).toBe(userId);
322+
expect(capturedSubject).not.toBe(fakeOrganization.organization.id);
323+
});
324+
288325
test('standalone API keys component in user context based on user_api_keys_enabled', async ({ page, context }) => {
289326
const u = createTestUtils({ app, page, context });
290327

packages/backend/src/api/__tests__/M2MTokenApi.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ describe('M2MToken', () => {
206206
});
207207
});
208208

209-
describe('verifyToken', () => {
209+
describe('verify', () => {
210210
it('verifies a m2m token using machine secret', async () => {
211211
const apiClient = createBackendApiClient({
212212
apiUrl: 'https://api.clerk.test',
@@ -223,7 +223,7 @@ describe('M2MToken', () => {
223223
),
224224
);
225225

226-
const response = await apiClient.m2m.verifyToken({
226+
const response = await apiClient.m2m.verify({
227227
token: m2mSecret,
228228
});
229229

@@ -249,7 +249,7 @@ describe('M2MToken', () => {
249249
),
250250
);
251251

252-
const response = await apiClient.m2m.verifyToken({
252+
const response = await apiClient.m2m.verify({
253253
token: m2mSecret,
254254
});
255255

@@ -274,7 +274,7 @@ describe('M2MToken', () => {
274274
);
275275

276276
const errResponse = await apiClient.m2m
277-
.verifyToken({
277+
.verify({
278278
token: m2mSecret,
279279
})
280280
.catch(err => err);

packages/backend/src/api/__tests__/factory.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ describe('api.client', () => {
325325
),
326326
);
327327

328-
const response = await apiClient.m2m.verifyToken({
328+
const response = await apiClient.m2m.verify({
329329
machineSecretKey: 'ak_test_in_header_params', // this will be added to headerParams.Authorization
330330
token: 'mt_secret_test',
331331
});
@@ -353,7 +353,7 @@ describe('api.client', () => {
353353
),
354354
);
355355

356-
const response = await apiClient.m2m.verifyToken({
356+
const response = await apiClient.m2m.verify({
357357
token: 'mt_secret_test',
358358
});
359359
expect(response.id).toBe('mt_test');
@@ -425,7 +425,7 @@ describe('api.client', () => {
425425
),
426426
);
427427

428-
const response = await apiClient.m2m.verifyToken({
428+
const response = await apiClient.m2m.verify({
429429
token: 'mt_secret_test',
430430
});
431431
expect(response.id).toBe('mt_test');

packages/backend/src/api/endpoints/APIKeysApi.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { ClerkPaginationRequest } from '@clerk/shared/types';
22

33
import type { PaginatedResourceResponse } from '../../api/resources/Deserializer';
44
import { joinPaths } from '../../util/path';
5+
import { deprecated } from '../../util/shared';
56
import type { APIKey } from '../resources/APIKey';
67
import { AbstractAPI } from './AbstractApi';
78

@@ -88,11 +89,19 @@ export class APIKeysAPI extends AbstractAPI {
8889
});
8990
}
9091

91-
async verifySecret(secret: string) {
92+
async verify(secret: string) {
9293
return this.request<APIKey>({
9394
method: 'POST',
9495
path: joinPaths(basePath, 'verify'),
9596
bodyParams: { secret },
9697
});
9798
}
99+
100+
/**
101+
* @deprecated Use `verify()` instead. This method will be removed in the next major release.
102+
*/
103+
async verifySecret(secret: string) {
104+
deprecated('apiKeys.verifySecret()', 'Use `apiKeys.verify()` instead.');
105+
return this.verify(secret);
106+
}
98107
}
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
import { joinPaths } from '../../util/path';
2+
import { deprecated } from '../../util/shared';
23
import type { IdPOAuthAccessToken } from '../resources';
34
import { AbstractAPI } from './AbstractApi';
45

56
const basePath = '/oauth_applications/access_tokens';
67

78
export class IdPOAuthAccessTokenApi extends AbstractAPI {
8-
async verifyAccessToken(accessToken: string) {
9+
async verify(accessToken: string) {
910
return this.request<IdPOAuthAccessToken>({
1011
method: 'POST',
1112
path: joinPaths(basePath, 'verify'),
1213
bodyParams: { access_token: accessToken },
1314
});
1415
}
16+
17+
/**
18+
* @deprecated Use `verify()` instead. This method will be removed in the next major release.
19+
*/
20+
async verifyAccessToken(accessToken: string) {
21+
deprecated('idPOAuthAccessToken.verifyAccessToken()', 'Use `idPOAuthAccessToken.verify()` instead.');
22+
return this.verify(accessToken);
23+
}
1524
}

packages/backend/src/api/endpoints/M2MTokenApi.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { joinPaths } from '../../util/path';
2+
import { deprecated } from '../../util/shared';
23
import type { ClerkBackendApiRequestOptions } from '../request';
34
import type { M2MToken } from '../resources/M2MToken';
45
import { AbstractAPI } from './AbstractApi';
@@ -94,7 +95,7 @@ export class M2MTokenApi extends AbstractAPI {
9495
return this.request<M2MToken>(requestOptions);
9596
}
9697

97-
async verifyToken(params: VerifyM2MTokenParams) {
98+
async verify(params: VerifyM2MTokenParams) {
9899
const { token, machineSecretKey } = params;
99100

100101
const requestOptions = this.#createRequestOptions(
@@ -108,4 +109,12 @@ export class M2MTokenApi extends AbstractAPI {
108109

109110
return this.request<M2MToken>(requestOptions);
110111
}
112+
113+
/**
114+
* @deprecated Use `verify()` instead. This method will be removed in the next major release.
115+
*/
116+
async verifyToken(params: VerifyM2MTokenParams) {
117+
deprecated('m2m.verifyToken()', 'Use `m2m.verify()` instead.');
118+
return this.verify(params);
119+
}
111120
}

packages/backend/src/tokens/verify.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ async function verifyM2MToken(
198198
): Promise<MachineTokenReturnType<M2MToken, MachineTokenVerificationError>> {
199199
try {
200200
const client = createBackendApiClient(options);
201-
const verifiedToken = await client.m2m.verifyToken({ token });
201+
const verifiedToken = await client.m2m.verify({ token });
202202
return { data: verifiedToken, tokenType: TokenType.M2MToken, errors: undefined };
203203
} catch (err: any) {
204204
return handleClerkAPIError(TokenType.M2MToken, err, 'Machine token not found');
@@ -211,7 +211,7 @@ async function verifyOAuthToken(
211211
): Promise<MachineTokenReturnType<IdPOAuthAccessToken, MachineTokenVerificationError>> {
212212
try {
213213
const client = createBackendApiClient(options);
214-
const verifiedToken = await client.idPOAuthAccessToken.verifyAccessToken(accessToken);
214+
const verifiedToken = await client.idPOAuthAccessToken.verify(accessToken);
215215
return { data: verifiedToken, tokenType: TokenType.OAuthToken, errors: undefined };
216216
} catch (err: any) {
217217
return handleClerkAPIError(TokenType.OAuthToken, err, 'OAuth token not found');
@@ -224,7 +224,7 @@ async function verifyAPIKey(
224224
): Promise<MachineTokenReturnType<APIKey, MachineTokenVerificationError>> {
225225
try {
226226
const client = createBackendApiClient(options);
227-
const verifiedToken = await client.apiKeys.verifySecret(secret);
227+
const verifiedToken = await client.apiKeys.verify(secret);
228228
return { data: verifiedToken, tokenType: TokenType.ApiKey, errors: undefined };
229229
} catch (err: any) {
230230
return handleClerkAPIError(TokenType.ApiKey, err, 'API key not found');

packages/shared/src/react/hooks/useAPIKeys.rq.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ export function useAPIKeys<T extends UseAPIKeysParams>(params?: T): UseAPIKeysRe
9393
const isEnabled = (safeValues.enabled ?? true) && clerk.loaded;
9494

9595
return usePagesOrInfinite({
96-
fetcher: clerk.apiKeys?.getAll ? (params: GetAPIKeysParams) => clerk.apiKeys.getAll(params) : undefined,
96+
fetcher: clerk.apiKeys?.getAll
97+
? (params: GetAPIKeysParams) => clerk.apiKeys.getAll({ ...params, subject: safeValues.subject })
98+
: undefined,
9799
config: {
98100
keepPreviousData: safeValues.keepPreviousData,
99101
infinite: safeValues.infinite,

packages/shared/src/react/hooks/useAPIKeys.swr.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ export function useAPIKeys<T extends UseAPIKeysParams>(params?: T): UseAPIKeysRe
9696
const isEnabled = (safeValues.enabled ?? true) && clerk.loaded;
9797

9898
const result = usePagesOrInfinite({
99-
fetcher: clerk.apiKeys?.getAll ? (params: GetAPIKeysParams) => clerk.apiKeys.getAll(params) : undefined,
99+
fetcher: clerk.apiKeys?.getAll
100+
? (params: GetAPIKeysParams) => clerk.apiKeys.getAll({ ...params, subject: safeValues.subject })
101+
: undefined,
100102
config: {
101103
keepPreviousData: safeValues.keepPreviousData,
102104
infinite: safeValues.infinite,

packages/testing/src/playwright/unstable/page-objects/userProfile.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ export const createUserProfileComponentPageObject = (testArgs: { page: EnhancedP
1717
switchToBillingTab: async () => {
1818
await page.getByText(/Billing/i).click();
1919
},
20+
switchToAPIKeysTab: async () => {
21+
await page.getByText(/API keys/i).click();
22+
},
2023
waitForMounted: () => {
2124
return page.waitForSelector('.cl-userProfile-root', { state: 'attached' });
2225
},

0 commit comments

Comments
 (0)