Skip to content

Commit f364924

Browse files
authored
fix(shared): Explicitly pass subject parameter to API keys fetcher hook (#7344)
1 parent e113464 commit f364924

File tree

5 files changed

+52
-2
lines changed

5 files changed

+52
-2
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@clerk/shared": patch
3+
"@clerk/testing": patch
4+
---
5+
6+
Fixed an issue where API keys in `<UserProfile />` are showing organization API keys.

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/shared/src/react/hooks/useAPIKeys.rq.tsx

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

9797
return usePagesOrInfinite({
98-
fetcher: clerk.apiKeys?.getAll ? (params: GetAPIKeysParams) => clerk.apiKeys.getAll(params) : undefined,
98+
fetcher: clerk.apiKeys?.getAll
99+
? (params: GetAPIKeysParams) => clerk.apiKeys.getAll({ ...params, subject: safeValues.subject })
100+
: undefined,
99101
config: {
100102
keepPreviousData: safeValues.keepPreviousData,
101103
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
@@ -98,7 +98,9 @@ export function useAPIKeys<T extends UseAPIKeysParams>(params?: T): UseAPIKeysRe
9898
const isEnabled = (safeValues.enabled ?? true) && clerk.loaded;
9999

100100
const result = usePagesOrInfinite({
101-
fetcher: clerk.apiKeys?.getAll ? (params: GetAPIKeysParams) => clerk.apiKeys.getAll(params) : undefined,
101+
fetcher: clerk.apiKeys?.getAll
102+
? (params: GetAPIKeysParams) => clerk.apiKeys.getAll({ ...params, subject: safeValues.subject })
103+
: undefined,
102104
config: {
103105
keepPreviousData: safeValues.keepPreviousData,
104106
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)