diff --git a/.changeset/gold-monkeys-collect.md b/.changeset/gold-monkeys-collect.md
new file mode 100644
index 0000000000..513f59c0f2
--- /dev/null
+++ b/.changeset/gold-monkeys-collect.md
@@ -0,0 +1,7 @@
+---
+'@clerk/clerk-js': patch
+'@clerk/nextjs': patch
+'@clerk/types': patch
+---
+
+Introduce `__internal_copyInstanceKeysUrl` as property in `ClerkOptions`. It is intented for internall usage from other Clerk SDKs and will be used in Keyless mode.
diff --git a/.changeset/twelve-spiders-obey.md b/.changeset/twelve-spiders-obey.md
new file mode 100644
index 0000000000..71e5b5a1bf
--- /dev/null
+++ b/.changeset/twelve-spiders-obey.md
@@ -0,0 +1,5 @@
+---
+'@clerk/backend': patch
+---
+
+Add property `api_keys_url` in the `AccountlessApplication` class
diff --git a/packages/backend/src/api/resources/AccountlessApplication.ts b/packages/backend/src/api/resources/AccountlessApplication.ts
index e4fe3dc46c..b74584ad7f 100644
--- a/packages/backend/src/api/resources/AccountlessApplication.ts
+++ b/packages/backend/src/api/resources/AccountlessApplication.ts
@@ -5,9 +5,10 @@ export class AccountlessApplication {
readonly publishableKey: string,
readonly secretKey: string,
readonly claimUrl: string,
+ readonly apiKeysUrl: string,
) {}
static fromJSON(data: AccountlessApplicationJSON): AccountlessApplication {
- return new AccountlessApplication(data.publishable_key, data.secret_key, data.claim_url);
+ return new AccountlessApplication(data.publishable_key, data.secret_key, data.claim_url, data.api_keys_url);
}
}
diff --git a/packages/backend/src/api/resources/JSON.ts b/packages/backend/src/api/resources/JSON.ts
index 077bba40f7..5ef4fb5d2a 100644
--- a/packages/backend/src/api/resources/JSON.ts
+++ b/packages/backend/src/api/resources/JSON.ts
@@ -54,6 +54,7 @@ export interface AccountlessApplicationJSON extends ClerkResourceJSON {
publishable_key: string;
secret_key: string;
claim_url: string;
+ api_keys_url: string;
}
export interface AllowlistIdentifierJSON extends ClerkResourceJSON {
diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts
index 6f2296558d..7234b7a254 100644
--- a/packages/clerk-js/src/core/clerk.ts
+++ b/packages/clerk-js/src/core/clerk.ts
@@ -2052,7 +2052,10 @@ export class Clerk implements ClerkInterface {
void this.#componentControls?.ensureMounted().then(controls => {
if (this.#options.__internal_claimKeylessApplicationUrl) {
controls.updateProps({
- options: { __internal_claimKeylessApplicationUrl: this.#options.__internal_claimKeylessApplicationUrl },
+ options: {
+ __internal_claimKeylessApplicationUrl: this.#options.__internal_claimKeylessApplicationUrl,
+ __internal_copyInstanceKeysUrl: this.#options.__internal_copyInstanceKeysUrl,
+ },
});
}
});
diff --git a/packages/clerk-js/src/ui/Components.tsx b/packages/clerk-js/src/ui/Components.tsx
index b5afeb1c79..43babfb850 100644
--- a/packages/clerk-js/src/ui/Components.tsx
+++ b/packages/clerk-js/src/ui/Components.tsx
@@ -518,9 +518,13 @@ const Components = (props: ComponentsProps) => {
)}
{__BUILD_FLAG_KEYLESS_UI__
- ? state.options?.__internal_claimKeylessApplicationUrl && (
+ ? state.options?.__internal_claimKeylessApplicationUrl &&
+ state.options?.__internal_copyInstanceKeysUrl && (
-
+
)
: null}
diff --git a/packages/clerk-js/src/ui/components/KeylessPrompt/index.tsx b/packages/clerk-js/src/ui/components/KeylessPrompt/index.tsx
index 3fa6ffd4ce..2ae30b92f0 100644
--- a/packages/clerk-js/src/ui/components/KeylessPrompt/index.tsx
+++ b/packages/clerk-js/src/ui/components/KeylessPrompt/index.tsx
@@ -1,3 +1,4 @@
+import { useClerk } from '@clerk/shared/react';
// eslint-disable-next-line no-restricted-imports
import { css } from '@emotion/react';
import { useState } from 'react';
@@ -9,12 +10,14 @@ import { ClerkLogoIcon } from './ClerkLogoIcon';
import { KeySlashIcon } from './KeySlashIcon';
type KeylessPromptProps = {
- url?: string;
+ claimUrl: string;
+ copyKeysUrl: string;
};
const _KeylessPrompt = (_props: KeylessPromptProps) => {
const [isExpanded, setIsExpanded] = useState(true);
const handleFocus = () => setIsExpanded(true);
+ const clerk = useClerk();
return (
@@ -310,6 +313,9 @@ const _KeylessPrompt = (_props: KeylessPromptProps) => {
type='button'
onFocus={handleFocus}
data-expanded={isExpanded}
+ onClick={() => {
+ void clerk.navigate(_props.claimUrl);
+ }}
css={css`
position: absolute;
right: 0.375rem;
diff --git a/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx b/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx
index 47d959dc96..6b575fe078 100644
--- a/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx
+++ b/packages/nextjs/src/app-router/client/keyless-creator-reader.tsx
@@ -20,6 +20,7 @@ export const KeylessCreatorOrReader = (props: NextClerkProviderProps) => {
key: state?.publishableKey,
publishableKey: state?.publishableKey,
__internal_claimKeylessApplicationUrl: state?.claimUrl,
+ __internal_copyInstanceKeysUrl: state?.apiKeysUrl,
__internal_bypassMissingPublishableKey: true,
} as any);
};
diff --git a/packages/nextjs/src/app-router/keyless-actions.ts b/packages/nextjs/src/app-router/keyless-actions.ts
index cf73d6b72a..ad2d43ef64 100644
--- a/packages/nextjs/src/app-router/keyless-actions.ts
+++ b/packages/nextjs/src/app-router/keyless-actions.ts
@@ -30,7 +30,7 @@ export async function createOrReadKeylessAction(): Promise
>;
+ /**
+ * The URL a developer should be redirected to in order to claim an instance created on Keyless mode.
+ */
__internal_claimKeylessApplicationUrl?: string;
+ /**
+ * After a developer has claimed their instance created by Keyless mode, they can use this URL to find their instance's keys
+ */
+ __internal_copyInstanceKeysUrl?: string;
+
/**
* [EXPERIMENTAL] Provide the underlying host router, required for the new experimental UI components.
*/