Skip to content

chore(repo): API Keys component integration tests #6107

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

Closed
wants to merge 122 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
cbee2b1
chore: set initial files for new component
wobsoriano May 5, 2025
c5c254d
chore: add resources and test methods
wobsoriano May 6, 2025
a1dfa60
chore(clerk-js): Remove Clerk.commerce (#5846)
brkalow May 6, 2025
cb1961e
chore: add simple table with calls to fapi
wobsoriano May 6, 2025
44cfd15
chore: use built in components
wobsoriano May 6, 2025
3a6d206
chore: add fake form
wobsoriano May 7, 2025
e4d26a5
chore: fix bad rebase
wobsoriano May 7, 2025
6a914c5
chore: fix bad rebase
wobsoriano May 7, 2025
beb0a44
chore: add create api key func
wobsoriano May 7, 2025
7294f7e
chore: add prop types and improve fetching
wobsoriano May 7, 2025
b2ff5a4
chore: add React component
wobsoriano May 7, 2025
83789d0
chore: accept props
wobsoriano May 7, 2025
de59b53
chore: add copy button functionality
wobsoriano May 7, 2025
3b4c715
chore: fetch secret on clipboard copy
wobsoriano May 7, 2025
b15610e
chore: add api key revokation
wobsoriano May 7, 2025
a0feb7a
chore: set minimum fields
wobsoriano May 8, 2025
a8a4f2f
chore: add pagination and improve form
wobsoriano May 8, 2025
ae65149
chore: try refetch
wobsoriano May 8, 2025
4b25f0f
chore: fix revalidation and more styling
wobsoriano May 9, 2025
69925f7
chore: rename component to <ApiKeys />
wobsoriano May 9, 2025
8de8219
chore: add expiration field
wobsoriano May 9, 2025
7c7e3e0
chore: add api keys component or user and org profile
wobsoriano May 9, 2025
f19825c
chore: add missing org profile sidebar nav
wobsoriano May 9, 2025
fb78ddc
chore: clean up props
wobsoriano May 9, 2025
0b2712c
chore: clean up props
wobsoriano May 9, 2025
ece97b3
chore: add api key secret fetcher and clean up components
wobsoriano May 13, 2025
bdecb55
chore: adjust table heading widths
wobsoriano May 13, 2025
1e338ec
chore: improve secret fetching
wobsoriano May 13, 2025
277b98c
chore: improve secret fetching
wobsoriano May 13, 2025
5faa5cf
chore: add locales
wobsoriano May 13, 2025
4377046
chore: action locales
wobsoriano May 13, 2025
137860c
chore: add locales to api keys page in user and org profile
wobsoriano May 14, 2025
5523b1a
chore: switch to swr for fetching
wobsoriano May 15, 2025
944ec76
chore: clean up fetchers and mutations
wobsoriano May 15, 2025
af99cab
chore: add initial error handling
wobsoriano May 15, 2025
b5c92e6
chore: add footer
wobsoriano May 16, 2025
0ee39fc
chore: add save button locale
wobsoriano May 16, 2025
57bf204
chore: fix close form btn
wobsoriano May 16, 2025
00d6d0b
chore: use description field and add custom expiration
wobsoriano May 16, 2025
f49a918
chore: add last used field
wobsoriano May 16, 2025
8ff06fe
chore: remove unused function
wobsoriano May 17, 2025
0f05f25
chore: add card width
wobsoriano May 17, 2025
7266d96
chore: add card width
wobsoriano May 17, 2025
6708873
chore: add custom page locales
wobsoriano May 19, 2025
6143e08
chore: rename component to APIKeys
wobsoriano May 19, 2025
bc0670a
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeysTable.tsx
wobsoriano May 20, 2025
2bdc6ff
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeysTable.tsx
wobsoriano May 20, 2025
2a0f715
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeysTable.tsx
wobsoriano May 20, 2025
0692f77
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeysTable.tsx
wobsoriano May 20, 2025
92c4c1d
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeysTable.tsx
wobsoriano May 20, 2025
75bc440
chore: adjustments to fetch calls
wobsoriano May 20, 2025
171a72b
chore: apply design suggestions
wobsoriano May 20, 2025
f520d87
chore: remove extra margin
wobsoriano May 20, 2025
14fa49b
chore: introduce revoke confirm dialog
wobsoriano May 23, 2025
44a3fe7
chore: make form and table responsive
wobsoriano May 23, 2025
c45b106
chore: clean up name casing
wobsoriano May 23, 2025
d0b4f05
chore: export APIKeys in nextjs
wobsoriano May 23, 2025
0b6de03
chore: fix merge conflicts
wobsoriano May 23, 2025
ee41a27
chore: add changeset
wobsoriano May 23, 2025
2b8096b
chore: update code icon
wobsoriano May 24, 2025
3375760
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
wobsoriano May 28, 2025
cd50d3e
chore: adjustments to table padding
wobsoriano May 28, 2025
d705977
chore: prevent layout shift in date input and segmented control buttons
wobsoriano May 28, 2025
0130c63
chore: move segmented control styling to root
wobsoriano May 28, 2025
6d25929
chore(clerk-js,types): Conditionally render API Keys page based on en…
wobsoriano May 30, 2025
163ff71
chore: remove unused component
wobsoriano May 30, 2025
2e38987
fix types
wobsoriano May 30, 2025
3cbf876
fix types
wobsoriano May 30, 2025
398cbfb
chore: update changesets
wobsoriano May 30, 2025
26c11b8
chore: fix snapshot tests
wobsoriano May 30, 2025
518dbbb
chore: fix react-router snapshot tests
wobsoriano May 30, 2025
4aea430
chore: fix chrome-extension snapshot tests
wobsoriano May 30, 2025
aa0adf6
chore: fix typedoc tests
wobsoriano May 30, 2025
c23d4b0
Update ApiKeysTable.tsx
wobsoriano Jun 2, 2025
8d09a9f
Update packages/localizations/src/de-DE.ts
wobsoriano Jun 3, 2025
6857961
Update packages/localizations/src/de-DE.ts
wobsoriano Jun 3, 2025
3380f9a
Update packages/localizations/src/de-DE.ts
wobsoriano Jun 3, 2025
bdef2fe
Update packages/localizations/src/de-DE.ts
wobsoriano Jun 3, 2025
aa69753
Update packages/localizations/src/de-DE.ts
wobsoriano Jun 3, 2025
87926e4
Update .changeset/ninety-candles-sleep.md
wobsoriano Jun 3, 2025
28894eb
Update .changeset/fluffy-numbers-stick.md
wobsoriano Jun 3, 2025
aac35e7
Apply suggestions from code review
wobsoriano Jun 3, 2025
3f7b3b2
fix: pass correct subject when used inside pages
wobsoriano Jun 3, 2025
d54ea6c
chore: update bundlewatch config
wobsoriano Jun 3, 2025
f0efd21
remove barrel files
wobsoriano Jun 3, 2025
24cb76d
chore: avoid barrel files
wobsoriano Jun 3, 2025
7a52029
Merge branch 'main' into rob/robo-20-manage-api-keys
wobsoriano Jun 5, 2025
062b2fe
fix incorrect merge
wobsoriano Jun 5, 2025
a996bbc
mark methods as experimental
wobsoriano Jun 5, 2025
666c0cb
adjust bundle size
wobsoriano Jun 5, 2025
bb96131
Merge branch 'main' into rob/robo-20-manage-api-keys
wobsoriano Jun 6, 2025
58b72f2
Merge branch 'main' into rob/robo-20-manage-api-keys
wobsoriano Jun 8, 2025
b180828
chore(clerk-js): Move API Keys methods to its own module (#6089)
wobsoriano Jun 8, 2025
2f87215
chore: localize time ago
wobsoriano Jun 10, 2025
e1e5b22
Merge branch 'main' into rob/robo-20-manage-api-keys
wobsoriano Jun 10, 2025
49643a4
chore: fix environment snapshot test
wobsoriano Jun 10, 2025
7874acc
chore: bundlewatch adjustment
wobsoriano Jun 10, 2025
44b06ca
Revert locale files to main except en-US and de-DE; keep customizations
wobsoriano Jun 10, 2025
cdeb9cb
chore: bundlewatch adjustment
wobsoriano Jun 10, 2025
3412b97
chore: bundlewatch adjustment
wobsoriano Jun 10, 2025
cee9cfa
chore: bundlewatch adjustment
wobsoriano Jun 10, 2025
9075be8
chore: type improvements
wobsoriano Jun 10, 2025
f568296
chore: fix remix snapshot tests
wobsoriano Jun 10, 2025
796ba7a
chore: pass error to be handled by client
wobsoriano Jun 10, 2025
09de7f8
fix revoke revalidation
wobsoriano Jun 10, 2025
7463647
Update packages/clerk-js/src/ui/components/ApiKeys/ApiKeys.tsx
wobsoriano Jun 10, 2025
90c3203
chore: revert
wobsoriano Jun 11, 2025
328a9ec
Merge branch 'main' into rob/robo-20-manage-api-keys
wobsoriano Jun 11, 2025
2d686b6
test: accommodate new snapshot test
wobsoriano Jun 11, 2025
2bfa305
chore: adjust bundlewatch config
wobsoriano Jun 11, 2025
6e73c4d
accommodate test file suffix changes
wobsoriano Jun 11, 2025
46ddfe9
Merge branch 'main' into rob/robo-20-manage-api-keys
wobsoriano Jun 11, 2025
7438cfb
chore: fix formatting
wobsoriano Jun 11, 2025
f2b0e1d
Update packages/clerk-js/src/core/resources/__tests__/Environment.spe…
wobsoriano Jun 11, 2025
37c91b9
chore: add session token check
wobsoriano Jun 12, 2025
195b770
chore: adjust bundlewatch config
wobsoriano Jun 12, 2025
5e2c11e
chore: make sure api keys feature is enabled before mounting
wobsoriano Jun 12, 2025
3952dd6
chore: adjust bundlewatch config
wobsoriano Jun 12, 2025
8eda216
chore: adjust bundlewatch config
wobsoriano Jun 12, 2025
906c587
chore: adjust bundlewatch config
wobsoriano Jun 12, 2025
b6e546e
chore: init
wobsoriano Jun 12, 2025
ad9ce96
more tests
wobsoriano Jun 12, 2025
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
6 changes: 6 additions & 0 deletions .changeset/fluffy-numbers-stick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/localizations': patch
'@clerk/types': patch
---

Add TypeScript types and en-US localization for upcoming `<APIKeys />` component. This component will initially be in early access.
7 changes: 7 additions & 0 deletions .changeset/ninety-candles-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/clerk-js': minor
'@clerk/nextjs': minor
'@clerk/clerk-react': minor
---

Add `<APIKeys />` component. This component will initially be in early access and not recommended for production usage just yet.
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ exports[`Typedoc output > should have a deliberate file structure 1`] = `
"nextjs/create-sync-get-auth.mdx",
"nextjs/current-user.mdx",
"nextjs/get-auth.mdx",
"clerk-react/api-keys.mdx",
"clerk-react/clerk-provider-props.mdx",
"clerk-react/protect.mdx",
"clerk-react/redirect-to-create-organization.mdx",
Expand Down
7 changes: 7 additions & 0 deletions integration/presets/envs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ const withWhatsappPhoneCode = base
.setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-whatsapp-phone-code').sk)
.setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-whatsapp-phone-code').pk);

const withAPIKeys = base
.clone()
.setId('withAPIKeys')
.setEnvVariable('private', 'CLERK_SECRET_KEY', instanceKeys.get('with-api-keys').sk)
.setEnvVariable('public', 'CLERK_PUBLISHABLE_KEY', instanceKeys.get('with-api-keys').pk);

export const envs = {
base,
withKeyless,
Expand All @@ -187,4 +193,5 @@ export const envs = {
withBillingStaging,
withBilling,
withWhatsappPhoneCode,
withAPIKeys,
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { APIKeys } from '@clerk/nextjs';

export default function APIKeysPage() {
return <APIKeys />;
}
63 changes: 63 additions & 0 deletions integration/tests/api-keys.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { test } from '@playwright/test';

import { appConfigs } from '../presets';
import type { FakeUser } from '../testUtils';
import { createTestUtils, testAgainstRunningApps } from '../testUtils';

testAgainstRunningApps({ withEnv: [appConfigs.envs.withAPIKeys] })('api keys @apiKeys', ({ app }) => {
test.describe.configure({ mode: 'serial' });

let fakeUser: FakeUser;

test.beforeAll(async () => {
const u = createTestUtils({ app });
fakeUser = u.services.users.createFakeUser();
await u.services.users.createBapiUser(fakeUser);
});

test.afterAll(async () => {
await fakeUser.deleteIfExists();
await app.teardown();
});

test.skip('can create an API key', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.po.signIn.goTo();
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
await u.po.page.goToRelative('/api-keys');

// TODO: Replace with custom page object
await u.po.page.waitForSelector('.cl-apiKeys-root');

await u.po.page.getByRole('button', { name: 'Add new key' }).click();
await u.po.page.locator('input[name=name]').fill('test-key');
});

test.skip('can create an API key with description and expiration', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.po.signIn.goTo();
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
await u.po.page.goToRelative('/api-keys');

// TODO: Replace with custom page object
await u.po.page.waitForSelector('.cl-apiKeys-root');

await u.po.page.getByRole('button', { name: 'Add new key' }).click();
await u.po.page.locator('input[name=name]').fill('test-key');

await u.po.page.getByRole('button', { name: 'Show advanced settings' }).click();

await u.po.page.locator('input[name=description]').fill('test-description');
await u.po.page.locator('input[name=expiration]').fill('2025-01-01');
});

test.skip('user is prompted before revoking and can revoke an API key', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.po.signIn.goTo();
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
await u.po.page.goToRelative('/api-keys');

// TODO: Replace with custom page object
await u.po.page.waitForSelector('.cl-apiKeys-root');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`public exports should not include a breaking change 1`] = `
[
"APIKeys",
"AuthenticateWithRedirectCallback",
"ClerkDegraded",
"ClerkFailed",
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "605kB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "69.2KB" },
{ "path": "./dist/clerk.js", "maxSize": "608.05kB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "70KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "113KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "53KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "106.3KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "107.33KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "38KB" },
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },
Expand Down
5 changes: 5 additions & 0 deletions packages/clerk-js/sandbox/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const AVAILABLE_COMPONENTS = [
'organizationSwitcher',
'waitlist',
'pricingTable',
'apiKeys',
'oauthConsent',
] as const;

Expand Down Expand Up @@ -92,6 +93,7 @@ const componentControls: Record<(typeof AVAILABLE_COMPONENTS)[number], Component
organizationSwitcher: buildComponentControls('organizationSwitcher'),
waitlist: buildComponentControls('waitlist'),
pricingTable: buildComponentControls('pricingTable'),
apiKeys: buildComponentControls('apiKeys'),
oauthConsent: buildComponentControls('oauthConsent'),
};

Expand Down Expand Up @@ -312,6 +314,9 @@ void (async () => {
'/pricing-table': () => {
Clerk.mountPricingTable(app, componentControls.pricingTable.getProps() ?? {});
},
'/api-keys': () => {
Clerk.mountApiKeys(app, componentControls.apiKeys.getProps() ?? {});
},
'/oauth-consent': () => {
const searchParams = new URLSearchParams(window.location.search);
const scopes = (searchParams.get('scopes')?.split(',') ?? []).map(scope => ({
Expand Down
8 changes: 8 additions & 0 deletions packages/clerk-js/sandbox/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,14 @@
PricingTable
</a>
</li>
<li class="relative">
<a
class="relative isolate flex w-full rounded-md border border-white px-2 py-[0.4375rem] text-sm hover:bg-gray-50 aria-[current]:bg-gray-50"
href="/api-keys"
>
API Keys
</a>
</li>
<li class="relative">
<a
class="relative isolate flex w-full rounded-md border border-white px-2 py-[0.4375rem] text-sm hover:bg-gray-50 aria-[current]:bg-gray-50"
Expand Down
55 changes: 55 additions & 0 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import type {
__internal_OAuthConsentProps,
__internal_PlanDetailsProps,
__internal_UserVerificationModalProps,
APIKeysNamespace,
APIKeysProps,
AuthenticateWithCoinbaseWalletParams,
AuthenticateWithGoogleOneTapParams,
AuthenticateWithMetamaskParams,
Expand Down Expand Up @@ -88,6 +90,7 @@ import {
createAllowedRedirectOrigins,
createBeforeUnloadTracker,
createPageLifecycle,
disabledAPIKeysFeature,
disabledBillingFeature,
disabledOrganizationsFeature,
errorThrower,
Expand Down Expand Up @@ -132,6 +135,7 @@ import { eventBus, events } from './events';
import type { FapiClient, FapiRequestCallback } from './fapiClient';
import { createFapiClient } from './fapiClient';
import { createClientFromJwt } from './jwt-client';
import { APIKeys } from './modules/apiKeys';
import { CommerceBilling } from './modules/commerce';
import {
BaseResource,
Expand Down Expand Up @@ -163,6 +167,7 @@ const CANNOT_RENDER_USER_MISSING_ERROR_CODE = 'cannot_render_user_missing';
const CANNOT_RENDER_ORGANIZATIONS_DISABLED_ERROR_CODE = 'cannot_render_organizations_disabled';
const CANNOT_RENDER_ORGANIZATION_MISSING_ERROR_CODE = 'cannot_render_organization_missing';
const CANNOT_RENDER_SINGLE_SESSION_ENABLED_ERROR_CODE = 'cannot_render_single_session_enabled';
const CANNOT_RENDER_API_KEYS_DISABLED_ERROR_CODE = 'cannot_render_api_keys_disabled';
const defaultOptions: ClerkOptions = {
polling: true,
standardBrowser: true,
Expand All @@ -189,6 +194,7 @@ export class Clerk implements ClerkInterface {
environment: process.env.NODE_ENV || 'production',
};
private static _billing: CommerceBillingNamespace;
private static _apiKeys: APIKeysNamespace;

public client: ClientResource | undefined;
public session: SignedInSessionResource | null | undefined;
Expand Down Expand Up @@ -324,6 +330,13 @@ export class Clerk implements ClerkInterface {
return Clerk._billing;
}

get apiKeys(): APIKeysNamespace {
if (!Clerk._apiKeys) {
Clerk._apiKeys = new APIKeys();
}
return Clerk._apiKeys;
}

public __internal_getOption<K extends keyof ClerkOptions>(key: K): ClerkOptions[K] {
return this.#options[key];
}
Expand Down Expand Up @@ -1055,6 +1068,48 @@ export class Clerk implements ClerkInterface {
void this.#componentControls.ensureMounted().then(controls => controls.unmountComponent({ node }));
};

/**
* @experimental
* This API is in early access and may change in future releases.
*
* Mount a api keys component at the target element.
* @param targetNode Target to mount the APIKeys component.
* @param props Configuration parameters.
*/
public mountApiKeys = (node: HTMLDivElement, props?: APIKeysProps) => {
this.assertComponentsReady(this.#componentControls);
if (disabledAPIKeysFeature(this, this.environment)) {
if (this.#instanceType === 'development') {
throw new ClerkRuntimeError(warnings.cannotRenderAPIKeysComponent, {
code: CANNOT_RENDER_API_KEYS_DISABLED_ERROR_CODE,
});
}
return;
}
void this.#componentControls.ensureMounted({ preloadHint: 'APIKeys' }).then(controls =>
controls.mountComponent({
name: 'APIKeys',
appearanceKey: 'apiKeys',
node,
props,
}),
);
};

/**
* @experimental
* This API is in early access and may change in future releases.
*
* Unmount a api keys component from the target element.
* If there is no component mounted at the target node, results in a noop.
*
* @param targetNode Target node to unmount the ApiKeys component from.
*/
public unmountApiKeys = (node: HTMLDivElement) => {
this.assertComponentsReady(this.#componentControls);
void this.#componentControls.ensureMounted().then(controls => controls.unmountComponent({ node }));
};

/**
* `setActive` can be used to set the active session and/or organization.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/core/fapiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ export function createFapiClient(options: FapiClientOptions): FapiClient {
const urlStr = requestInit.url.toString();
const fetchOpts: FapiRequestInit = {
...requestInit,
credentials: 'include',
method: overwrittenRequestMethod,
credentials: requestInit.credentials || 'include',
};

try {
Expand Down
103 changes: 103 additions & 0 deletions packages/clerk-js/src/core/modules/apiKeys/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import type {
ApiKeyJSON,
APIKeyResource,
APIKeysNamespace,
CreateAPIKeyParams,
GetAPIKeysParams,
RevokeAPIKeyParams,
} from '@clerk/types';

import type { FapiRequestInit } from '@/core/fapiClient';

import { APIKey, BaseResource, ClerkRuntimeError } from '../../resources/internal';

export class APIKeys implements APIKeysNamespace {
/**
* Returns the base options for the FAPI proxy requests.
*/
private async getBaseFapiProxyOptions(): Promise<FapiRequestInit> {
const token = await BaseResource.clerk.session?.getToken();
if (!token) {
throw new ClerkRuntimeError('No valid session token available', { code: 'no_session_token' });
}

return {
// Set to an empty string because FAPI Proxy does not include the version in the path.
pathPrefix: '',
// Set the session token as a Bearer token in the Authorization header for authentication.
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
// Set to `same-origin` to ensure cookies and credentials are sent with requests, avoiding CORS issues.
credentials: 'same-origin',
};
}

async getAll(params?: GetAPIKeysParams): Promise<APIKeyResource[]> {
return BaseResource.clerk
.getFapiClient()
.request<{ api_keys: ApiKeyJSON[] }>({
...(await this.getBaseFapiProxyOptions()),
method: 'GET',
path: '/api_keys',
search: {
subject: params?.subject ?? BaseResource.clerk.organization?.id ?? BaseResource.clerk.user?.id ?? '',
},
})
.then(res => {
const apiKeysJSON = res.payload as unknown as { api_keys: ApiKeyJSON[] };
return apiKeysJSON.api_keys.map(json => new APIKey(json));
})
.catch(() => []);
}

async getSecret(id: string): Promise<string> {
return BaseResource.clerk
.getFapiClient()
.request<{ secret: string }>({
...(await this.getBaseFapiProxyOptions()),
method: 'GET',
path: `/api_keys/${id}/secret`,
})
.then(res => {
const { secret } = res.payload as unknown as { secret: string };
return secret;
})
.catch(() => '');
}

async create(params: CreateAPIKeyParams): Promise<APIKeyResource> {
const json = (
await BaseResource._fetch<ApiKeyJSON>({
...(await this.getBaseFapiProxyOptions()),
path: '/api_keys',
method: 'POST',
body: JSON.stringify({
type: params.type ?? 'api_key',
name: params.name,
subject: params.subject ?? BaseResource.clerk.organization?.id ?? BaseResource.clerk.user?.id ?? '',
description: params.description,
seconds_until_expiration: params.secondsUntilExpiration,
}),
})
)?.response as ApiKeyJSON;

return new APIKey(json);
}

async revoke(params: RevokeAPIKeyParams): Promise<APIKeyResource> {
const json = (
await BaseResource._fetch<ApiKeyJSON>({
...(await this.getBaseFapiProxyOptions()),
method: 'POST',
path: `/api_keys/${params.apiKeyID}/revoke`,
body: JSON.stringify({
revocation_reason: params.revocationReason,
}),
})
)?.response as ApiKeyJSON;

return new APIKey(json);
}
}
Loading