diff --git a/.changeset/nice-seas-vue-nuxt-oauth-consent.md b/.changeset/nice-seas-vue-nuxt-oauth-consent.md
new file mode 100644
index 00000000000..d692c1bbe31
--- /dev/null
+++ b/.changeset/nice-seas-vue-nuxt-oauth-consent.md
@@ -0,0 +1,18 @@
+---
+"@clerk/nuxt": minor
+"@clerk/vue": minor
+---
+
+Expose `OAuthConsent` as a public component export for Vue and Nuxt.
+
+Example:
+
+```vue
+
+
+
+
+
+```
diff --git a/.changeset/small-planets-astro-oauth-consent.md b/.changeset/small-planets-astro-oauth-consent.md
new file mode 100644
index 00000000000..dea7af1efda
--- /dev/null
+++ b/.changeset/small-planets-astro-oauth-consent.md
@@ -0,0 +1,15 @@
+---
+"@clerk/astro": minor
+---
+
+Expose `OAuthConsent` as a public component export for Astro.
+
+Example:
+
+```astro
+---
+import { OAuthConsent } from '@clerk/astro/components';
+---
+
+
+```
diff --git a/.changeset/three-rabbits-react-oauth-consent.md b/.changeset/three-rabbits-react-oauth-consent.md
new file mode 100644
index 00000000000..3817811b77f
--- /dev/null
+++ b/.changeset/three-rabbits-react-oauth-consent.md
@@ -0,0 +1,21 @@
+---
+"@clerk/clerk-js": minor
+"@clerk/nextjs": minor
+"@clerk/react": minor
+"@clerk/react-router": minor
+"@clerk/shared": minor
+"@clerk/tanstack-react-start": minor
+"@clerk/ui": minor
+---
+
+Expose `OAuthConsent` as a public component export across React-based SDKs.
+
+Example:
+
+```tsx
+import { OAuthConsent } from '@clerk/react';
+
+export default function Page() {
+ return ;
+}
+```
diff --git a/packages/astro/src/astro-components/index.ts b/packages/astro/src/astro-components/index.ts
index f4472c143f9..0f02bca09ff 100644
--- a/packages/astro/src/astro-components/index.ts
+++ b/packages/astro/src/astro-components/index.ts
@@ -28,5 +28,6 @@ export { default as OrganizationList } from './interactive/OrganizationList.astr
export { default as CreateOrganization } from './interactive/CreateOrganization.astro';
export { default as GoogleOneTap } from './interactive/GoogleOneTap.astro';
export { default as Waitlist } from './interactive/Waitlist.astro';
+export { default as OAuthConsent } from './interactive/OAuthConsent.astro';
export { default as PricingTable } from './interactive/PricingTable.astro';
export { default as APIKeys } from './interactive/APIKeys.astro';
diff --git a/packages/astro/src/astro-components/interactive/OAuthConsent.astro b/packages/astro/src/astro-components/interactive/OAuthConsent.astro
new file mode 100644
index 00000000000..dabb9223ae4
--- /dev/null
+++ b/packages/astro/src/astro-components/interactive/OAuthConsent.astro
@@ -0,0 +1,11 @@
+---
+import type { OAuthConsentProps } from '@clerk/shared/types';
+type Props = OAuthConsentProps;
+
+import InternalUIComponentRenderer from './InternalUIComponentRenderer.astro';
+---
+
+
diff --git a/packages/astro/src/internal/mount-clerk-astro-js-components.ts b/packages/astro/src/internal/mount-clerk-astro-js-components.ts
index bb4807aacf1..97720d3de67 100644
--- a/packages/astro/src/internal/mount-clerk-astro-js-components.ts
+++ b/packages/astro/src/internal/mount-clerk-astro-js-components.ts
@@ -21,6 +21,7 @@ const mountAllClerkAstroJSComponents = () => {
waitlist: 'mountWaitlist',
'pricing-table': 'mountPricingTable',
'api-keys': 'mountAPIKeys',
+ 'oauth-consent': 'mountOAuthConsent',
} as const satisfies Record;
Object.entries(mountFns).forEach(([category, mountFn]) => {
diff --git a/packages/astro/src/react/uiComponents.tsx b/packages/astro/src/react/uiComponents.tsx
index 8a7be514e15..e8d420e82da 100644
--- a/packages/astro/src/react/uiComponents.tsx
+++ b/packages/astro/src/react/uiComponents.tsx
@@ -1,5 +1,6 @@
import type {
GoogleOneTapProps,
+ OAuthConsentProps,
OrganizationListProps,
OrganizationProfileProps,
OrganizationSwitcherProps,
@@ -196,3 +197,13 @@ export const PricingTable = withClerk(({ clerk, ...props }: WithClerkProp
);
}, 'PricingTable');
+
+export const OAuthConsent = withClerk(({ clerk, ...props }: WithClerkProp) => {
+ return (
+
+ );
+}, 'OAuthConsent');
diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts
index 2248d5ce1f3..5807f6c3b3e 100644
--- a/packages/astro/src/types.ts
+++ b/packages/astro/src/types.ts
@@ -119,4 +119,5 @@ export type InternalUIComponentId =
| 'google-one-tap'
| 'waitlist'
| 'pricing-table'
- | 'api-keys';
+ | 'api-keys'
+ | 'oauth-consent';
diff --git a/packages/clerk-js/sandbox/app.ts b/packages/clerk-js/sandbox/app.ts
index 064c740eb27..37b6433e226 100644
--- a/packages/clerk-js/sandbox/app.ts
+++ b/packages/clerk-js/sandbox/app.ts
@@ -475,7 +475,7 @@ void (async () => {
description: scope === 'offline_access' ? null : `Grants access to your ${scope}`,
requires_consent: true,
}));
- Clerk.__internal_mountOAuthConsent(
+ Clerk.mountOAuthConsent(
app,
componentControls.oauthConsent.getProps() ?? {
scopes,
diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts
index 47cbfb2515f..1283fae8960 100644
--- a/packages/clerk-js/src/core/clerk.ts
+++ b/packages/clerk-js/src/core/clerk.ts
@@ -95,6 +95,7 @@ import type {
LoadedClerk,
NavigateOptions,
OAuthApplicationNamespace,
+ OAuthConsentProps,
OrganizationListProps,
OrganizationProfileProps,
OrganizationResource,
@@ -1348,7 +1349,7 @@ export class Clerk implements ClerkInterface {
void this.#clerkUI?.then(ui => ui.ensureMounted()).then(controls => controls.unmountComponent({ node }));
};
- public __internal_mountOAuthConsent = (node: HTMLDivElement, props?: __internal_OAuthConsentProps) => {
+ public mountOAuthConsent = (node: HTMLDivElement, props?: OAuthConsentProps) => {
if (noUserExists(this)) {
if (this.#instanceType === 'development') {
throw new ClerkRuntimeError(warnings.cannotRenderOAuthConsentComponentWhenUserDoesNotExist, {
@@ -1372,10 +1373,24 @@ export class Clerk implements ClerkInterface {
);
};
- public __internal_unmountOAuthConsent = (node: HTMLDivElement) => {
+ public unmountOAuthConsent = (node: HTMLDivElement) => {
void this.#clerkUI?.then(ui => ui.ensureMounted()).then(controls => controls.unmountComponent({ node }));
};
+ /**
+ * @deprecated Use mountOAuthConsent instead.
+ */
+ public __internal_mountOAuthConsent = (node: HTMLDivElement, props?: __internal_OAuthConsentProps) => {
+ return this.mountOAuthConsent(node, props);
+ };
+
+ /**
+ * @deprecated Use unmountOAuthConsent instead.
+ */
+ public __internal_unmountOAuthConsent = (node: HTMLDivElement) => {
+ return this.unmountOAuthConsent(node);
+ };
+
/**
* Mount an API keys component at the target element.
* @param targetNode Target to mount the APIKeys component.
diff --git a/packages/nextjs/src/client-boundary/hooks.ts b/packages/nextjs/src/client-boundary/hooks.ts
index 73b5e14da4f..4527d8efc22 100644
--- a/packages/nextjs/src/client-boundary/hooks.ts
+++ b/packages/nextjs/src/client-boundary/hooks.ts
@@ -4,6 +4,7 @@ export {
useAuth,
useClerk,
useEmailLink,
+ useOAuthConsent,
useOrganization,
useOrganizationList,
useOrganizationCreationDefaults,
diff --git a/packages/nextjs/src/client-boundary/uiComponents.tsx b/packages/nextjs/src/client-boundary/uiComponents.tsx
index 9fd5a6d6d37..f6f65fad650 100644
--- a/packages/nextjs/src/client-boundary/uiComponents.tsx
+++ b/packages/nextjs/src/client-boundary/uiComponents.tsx
@@ -15,6 +15,8 @@ export {
APIKeys,
CreateOrganization,
GoogleOneTap,
+ HandleSSOCallback,
+ OAuthConsent,
OrganizationList,
OrganizationSwitcher,
PricingTable,
@@ -28,11 +30,8 @@ export {
UserAvatar,
UserButton,
Waitlist,
- HandleSSOCallback,
} from '@clerk/react';
-export { OAuthConsent } from '@clerk/react/internal';
-
// The assignment of UserProfile with BaseUserProfile props is used
// to support the CustomPage functionality (eg UserProfile.Page)
// Also the `typeof BaseUserProfile` is used to resolve the following error:
diff --git a/packages/nextjs/src/index.ts b/packages/nextjs/src/index.ts
index 25cea1d9d19..283a7935cfc 100644
--- a/packages/nextjs/src/index.ts
+++ b/packages/nextjs/src/index.ts
@@ -25,6 +25,7 @@ export {
APIKeys,
CreateOrganization,
GoogleOneTap,
+ OAuthConsent,
OrganizationList,
OrganizationProfile,
OrganizationSwitcher,
@@ -52,6 +53,7 @@ export {
useAuth,
useClerk,
useEmailLink,
+ useOAuthConsent,
useOrganization,
useOrganizationCreationDefaults,
useOrganizationList,
diff --git a/packages/nextjs/src/internal.ts b/packages/nextjs/src/internal.ts
index be6d80fb216..0e86e4ab0ff 100644
--- a/packages/nextjs/src/internal.ts
+++ b/packages/nextjs/src/internal.ts
@@ -2,6 +2,19 @@
* These need to be explicitly listed. Do not use an * here.
* If you do, app router will break.
*/
+import { OAuthConsent as OAuthConsentOriginal } from './client-boundary/uiComponents';
+import { useOAuthConsent as useOAuthConsentOriginal } from '@clerk/shared/react';
+
export { MultisessionAppSupport } from './client-boundary/controlComponents';
-export { OAuthConsent } from './client-boundary/uiComponents';
-export { useOAuthConsent } from '@clerk/shared/react';
+
+/**
+ * @deprecated Import `OAuthConsent` from `@clerk/nextjs` instead.
+ */
+const OAuthConsent = OAuthConsentOriginal;
+export { OAuthConsent };
+
+/**
+ * @deprecated Import `useOAuthConsent` from `@clerk/nextjs` instead.
+ */
+const useOAuthConsent = useOAuthConsentOriginal;
+export { useOAuthConsent };
diff --git a/packages/nuxt/src/runtime/components/index.ts b/packages/nuxt/src/runtime/components/index.ts
index 60a99d69241..0d73def7d8c 100644
--- a/packages/nuxt/src/runtime/components/index.ts
+++ b/packages/nuxt/src/runtime/components/index.ts
@@ -5,6 +5,7 @@ export {
UserButton,
OrganizationSwitcher,
GoogleOneTap,
+ OAuthConsent,
Waitlist,
// Control components
ClerkLoaded,
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index 3d5096c96c4..f0e3adf8c4a 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -42,10 +42,6 @@
"types": "./dist/api/index.d.ts",
"default": "./dist/api/index.js"
},
- "./internal": {
- "types": "./dist/internal.d.ts",
- "default": "./dist/internal.js"
- },
"./errors": {
"types": "./dist/errors.d.ts",
"default": "./dist/errors.js"
@@ -77,9 +73,6 @@
"api.server": [
"dist/api/index.d.ts"
],
- "internal": [
- "dist/internal.d.ts"
- ],
"webhooks": [
"dist/webhooks.d.ts"
],
diff --git a/packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap b/packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap
index de4f6bb566c..27525d4ce63 100644
--- a/packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap
+++ b/packages/react-router/src/__tests__/__snapshots__/exports.test.ts.snap
@@ -26,6 +26,7 @@ exports[`root public exports > should not change unexpectedly 1`] = `
"CreateOrganization",
"GoogleOneTap",
"HandleSSOCallback",
+ "OAuthConsent",
"OrganizationList",
"OrganizationProfile",
"OrganizationSwitcher",
@@ -61,6 +62,7 @@ exports[`root public exports > should not change unexpectedly 1`] = `
"useAuth",
"useClerk",
"useEmailLink",
+ "useOAuthConsent",
"useOrganization",
"useOrganizationCreationDefaults",
"useOrganizationList",
diff --git a/packages/react-router/src/internal.ts b/packages/react-router/src/internal.ts
deleted file mode 100644
index 14f123a78ba..00000000000
--- a/packages/react-router/src/internal.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { useOAuthConsent, OAuthConsent } from '@clerk/react/internal';
diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts
index c01f3171d25..0cec6374f29 100644
--- a/packages/react/src/components/index.ts
+++ b/packages/react/src/components/index.ts
@@ -2,6 +2,7 @@ export {
APIKeys,
CreateOrganization,
GoogleOneTap,
+ OAuthConsent,
OrganizationList,
OrganizationProfile,
OrganizationSwitcher,
diff --git a/packages/react/src/hooks/index.ts b/packages/react/src/hooks/index.ts
index 0db65cab7f7..e33d87ea1c6 100644
--- a/packages/react/src/hooks/index.ts
+++ b/packages/react/src/hooks/index.ts
@@ -11,6 +11,7 @@ export {
useSession,
useReverification,
useAPIKeys,
+ useOAuthConsent,
__experimental_useCheckout,
__experimental_CheckoutProvider,
__experimental_usePaymentElement,
diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts
index 99f90c77fbe..c723b95ce33 100644
--- a/packages/react/src/internal.ts
+++ b/packages/react/src/internal.ts
@@ -1,15 +1,28 @@
+import { useOAuthConsent as useOAuthConsentOriginal } from '@clerk/shared/react';
import type { InternalClerkScriptProps } from '@clerk/shared/types';
import type { Ui } from '@clerk/ui/internal';
import type React from 'react';
+import { OAuthConsent as OAuthConsentOriginal } from './components/uiComponents';
import { ClerkProvider } from './contexts/ClerkProvider';
import type { ClerkProviderProps } from './types';
export { publishableKeyFromHost } from '@clerk/shared/keys';
export { setErrorThrowerOptions } from './errors/errorThrower';
export { MultisessionAppSupport } from './components/controlComponents';
-export { useOAuthConsent } from '@clerk/shared/react';
-export { OAuthConsent } from './components/uiComponents';
+
+/**
+ * @deprecated Import `useOAuthConsent` from `@clerk/react` instead.
+ */
+const useOAuthConsent = useOAuthConsentOriginal;
+export { useOAuthConsent };
+
+/**
+ * @deprecated Import `OAuthConsent` from `@clerk/react` instead.
+ */
+const OAuthConsent = OAuthConsentOriginal;
+export { OAuthConsent };
+
export { useRoutingProps } from './hooks/useRoutingProps';
export { useDerivedAuth } from './hooks/useAuth';
export { IS_REACT_SHARED_VARIANT_COMPATIBLE } from './utils/versionCheck';
diff --git a/packages/react/src/isomorphicClerk.ts b/packages/react/src/isomorphicClerk.ts
index 32b050d36c4..b47acb36f15 100644
--- a/packages/react/src/isomorphicClerk.ts
+++ b/packages/react/src/isomorphicClerk.ts
@@ -36,6 +36,7 @@ import type {
ListenerOptions,
LoadedClerk,
OAuthApplicationNamespace,
+ OAuthConsentProps,
OrganizationListProps,
OrganizationProfileProps,
OrganizationResource,
@@ -1298,6 +1299,14 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
}
};
+ mountOAuthConsent = (node: HTMLDivElement, props?: OAuthConsentProps) => {
+ this.__internal_mountOAuthConsent(node, props);
+ };
+
+ unmountOAuthConsent = (node: HTMLDivElement) => {
+ this.__internal_unmountOAuthConsent(node);
+ };
+
mountTaskChooseOrganization = (node: HTMLDivElement, props?: TaskChooseOrganizationProps): void => {
if (this.clerkjs && this.loaded) {
this.clerkjs.mountTaskChooseOrganization(node, props);
diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts
index f4ab6a08140..8611121251d 100644
--- a/packages/shared/src/types/clerk.ts
+++ b/packages/shared/src/types/clerk.ts
@@ -676,6 +676,21 @@ export interface Clerk {
*/
__internal_unmountOAuthConsent: (targetNode: HTMLDivElement) => void;
+ /**
+ * Mounts a OAuth consent component at the target element.
+ *
+ * @param targetNode - Target node to mount the OAuth consent component.
+ * @param oauthConsentProps - OAuth consent configuration parameters.
+ */
+ mountOAuthConsent: (targetNode: HTMLDivElement, oauthConsentProps?: OAuthConsentProps) => void;
+
+ /**
+ * Unmounts a OAuth consent component from the target element.
+ *
+ * @param targetNode - Target node to unmount the OAuth consent component from.
+ */
+ unmountOAuthConsent: (targetNode: HTMLDivElement) => void;
+
/**
* Mounts a TaskChooseOrganization component at the target element.
*
@@ -2265,7 +2280,7 @@ export type __experimental_SubscriptionDetailsButtonProps = {
};
};
-export type __internal_OAuthConsentProps = {
+export type OAuthConsentProps = {
/**
* Customize the appearance of the component.
*/
@@ -2328,6 +2343,9 @@ export type __internal_OAuthConsentProps = {
onDeny?: () => void;
};
+/** @deprecated Use OAuthConsentProps instead. */
+export type __internal_OAuthConsentProps = OAuthConsentProps;
+
export interface HandleEmailLinkVerificationParams {
/**
* Full URL or path to navigate to after successful magic link verification
diff --git a/packages/tanstack-react-start/package.json b/packages/tanstack-react-start/package.json
index 687c5dfef85..f289826be6a 100644
--- a/packages/tanstack-react-start/package.json
+++ b/packages/tanstack-react-start/package.json
@@ -35,10 +35,6 @@
"types": "./dist/server/index.d.ts",
"default": "./dist/server/index.js"
},
- "./internal": {
- "types": "./dist/internal.d.ts",
- "default": "./dist/internal.js"
- },
"./errors": {
"types": "./dist/errors.d.ts",
"default": "./dist/errors.js"
diff --git a/packages/tanstack-react-start/src/__tests__/__snapshots__/exports.test.ts.snap b/packages/tanstack-react-start/src/__tests__/__snapshots__/exports.test.ts.snap
index 1df121af672..4a5318392ee 100644
--- a/packages/tanstack-react-start/src/__tests__/__snapshots__/exports.test.ts.snap
+++ b/packages/tanstack-react-start/src/__tests__/__snapshots__/exports.test.ts.snap
@@ -32,6 +32,7 @@ exports[`root public exports > should not change unexpectedly 1`] = `
"CreateOrganization",
"GoogleOneTap",
"HandleSSOCallback",
+ "OAuthConsent",
"OrganizationList",
"OrganizationProfile",
"OrganizationSwitcher",
@@ -67,6 +68,7 @@ exports[`root public exports > should not change unexpectedly 1`] = `
"useAuth",
"useClerk",
"useEmailLink",
+ "useOAuthConsent",
"useOrganization",
"useOrganizationCreationDefaults",
"useOrganizationList",
diff --git a/packages/tanstack-react-start/src/internal.ts b/packages/tanstack-react-start/src/internal.ts
deleted file mode 100644
index 14f123a78ba..00000000000
--- a/packages/tanstack-react-start/src/internal.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { useOAuthConsent, OAuthConsent } from '@clerk/react/internal';
diff --git a/packages/ui/src/components/OAuthConsent/__tests__/OAuthConsent.test.tsx b/packages/ui/src/components/OAuthConsent/__tests__/OAuthConsent.test.tsx
index dce4347d6fd..3893619c3c4 100644
--- a/packages/ui/src/components/OAuthConsent/__tests__/OAuthConsent.test.tsx
+++ b/packages/ui/src/components/OAuthConsent/__tests__/OAuthConsent.test.tsx
@@ -208,9 +208,9 @@ describe('OAuthConsent', () => {
f.withUser({ email_addresses: ['jane@example.com'] });
});
- // Simulate the accounts portal path: `clerk.__internal_mountOAuthConsent` is
+ // Simulate the accounts portal path: `clerk.mountOAuthConsent` is
// called with the legacy `oAuth*` (capital-A) prop shape from
- // `__internal_OAuthConsentProps`. The `ComponentContextProvider` translates
+ // `OAuthConsentProps`. The `ComponentContextProvider` translates
// these to the lowercase `oauth*` shape that the component reads from context
// (see the `case 'OAuthConsent':` block in ClerkUIComponentsContext.tsx).
// This test verifies the translation end-to-end: if it were broken, the
diff --git a/packages/ui/src/contexts/ClerkUIComponentsContext.tsx b/packages/ui/src/contexts/ClerkUIComponentsContext.tsx
index 3b27bf9aa63..282160cf2af 100644
--- a/packages/ui/src/contexts/ClerkUIComponentsContext.tsx
+++ b/packages/ui/src/contexts/ClerkUIComponentsContext.tsx
@@ -1,5 +1,5 @@
import type {
- __internal_OAuthConsentProps,
+ OAuthConsentProps,
APIKeysProps,
PricingTableProps,
TaskChooseOrganizationProps,
@@ -119,7 +119,7 @@ export function ComponentContextProvider({
// the lowercase `oauth*` context shape the component reads.
// The public `` wrapper also forwards `oauthClientId`
// and `scope` through the same path.
- const p = props as __internal_OAuthConsentProps;
+ const p = props as OAuthConsentProps;
return (
+import { ClerkHostRenderer } from '../ClerkHostRenderer';
+import type { OAuthConsentProps } from '@clerk/shared/types';
+import { useClerk } from '../../composables';
+
+const clerk = useClerk();
+const props = defineProps();
+
+
+
+
+