From 69dac721854728d7599b32c028c3cd899370ad1f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 14 Apr 2026 17:53:01 -0700 Subject: [PATCH 1/4] docs: add accounts portal OAuth consent refactor spec --- ...-accounts-oauth-consent-refactor-design.md | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md diff --git a/docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md b/docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md new file mode 100644 index 00000000000..212aab20054 --- /dev/null +++ b/docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md @@ -0,0 +1,88 @@ +# Accounts Portal OAuth Consent Refactor Design + +> **For agentic workers:** This spec targets the accounts repo at `/Users/wobsoriano/Documents/projects/clerk/accounts`, not the javascript repo. + +**Goal:** Replace the accounts portal's manual OAuth consent implementation with the new `` component from `@clerk/nextjs/internal`, deleting all custom fetch utilities, hidden forms, and types in the process. + +**Context:** The `OAuthConsent` component (in `packages/ui`) now handles the full public path: it reads `client_id`, `redirect_uri`, and `scope` from the URL, fetches consent info via `clerk.oauthApplication.getConsentInfo`, renders scopes, and submits the consent form to `clerk.oauthApplication.buildConsentActionUrl`. The accounts portal's manual implementation duplicates all of this and can be deleted entirely. + +--- + +## Files Deleted + +- `components/oauth-consent/index.tsx` — manual fetch + `__internal_mountOAuthConsent` + hidden forms +- `utils/oauth-consent.ts` — `getConsentInfoForOAuth` FAPI fetch utility +- `types/OAuthConsent.ts` — `OAuthConsentInfo` type (only used by the above two files) + +## Files Modified + +### `types/index.ts` + +Remove the re-export of the deleted type file: + +```diff +- export * from './OAuthConsent'; + export * from './AccountPortalJSON'; + export * from './constants'; +``` + +`constants.ts` and `AccountPortalJSON.ts` are untouched — `DEV_BROWSER_JWT_MARKER` and `CLIENT_COOKIE_NAME` are still used elsewhere. + +### `pages/oauth-consent/[[...index]].tsx` + +Replace the entire file. `getServerSideProps` is removed — clerk-js handles `devBrowserJWT` and session auth automatically, and the new component reads all params from `window.location.search`. The referrer meta tag is kept (FAPI requires the `Origin` header on consent form POSTs). + +```tsx +import React from 'react'; +import Head from 'next/head'; +import { OAuthConsent } from '@clerk/nextjs/internal'; + +export default function ConsentPage(): JSX.Element { + return ( +
+
+ + + + +
+
+ ); +} +``` + +### `e2e/features/oauth-consent.test.ts` + +Error message text changes to match the new component's wording. Happy path assertion changes from hidden inputs (old hidden forms) to the Allow/Deny buttons the new component renders. + +| Old assertion | New assertion | +| --------------------------------------------------------- | ----------------------------------------- | +| `'Error: Authorization failed: The client ID is missing'` | `'The client ID is missing.'` | +| `'Error: Redirect URI not found'` | `'The redirect URI is missing.'` | +| `input[name="consented"][value="true"]` | `button[name="consented"][value="true"]` | +| `input[name="consented"][value="false"]` | `button[name="consented"][value="false"]` | + +### `e2e/unauthenticated/oauth-consent.test.ts` + +The old component returned an explicit `"Error: No session found"` div. The new component is wrapped with `withCoreUserGuard` which renders `null` for unauthenticated users. Update both tests to assert that the Allow button is not visible instead. + +```ts +// Before +await expect(page.getByText('Error: No session found')).toBeVisible(); + +// After +await expect(page.getByRole('button', { name: 'Allow' })).not.toBeVisible(); +``` + +--- + +## What Is Not Changing + +- `types/constants.ts` — stays, used by `utils/devBrowser.ts`, `utils/settings/environment.ts`, `utils/settings/accountPortal.ts` +- `utils/devBrowser.ts` — stays, unrelated to OAuth consent +- The page URL (`/oauth-consent`) and its Next.js route — unchanged +- The referrer meta tag — kept +- CSS class names (`pageContainer`, `componentContainer`) — unchanged From 2c3368465312d2a323d4a68de548d939c05b66a8 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 22 Apr 2026 11:05:09 -0700 Subject: [PATCH 2/4] feat: promote OAuthConsent to public API across all SDKs - Rename __internal_OAuthConsentProps to OAuthConsentProps in @clerk/shared - Rename __internal_mountOAuthConsent / __internal_unmountOAuthConsent to mountOAuthConsent / unmountOAuthConsent on the Clerk interface and clerk-js - Add OAuthConsent and useOAuthConsent to the public exports of @clerk/react, @clerk/nextjs, @clerk/vue, @clerk/nuxt, and @clerk/astro - Add @deprecated JSDoc to the existing /internal re-exports in @clerk/react and @clerk/nextjs pointing consumers to the public paths - Update @clerk/ui type references to the renamed public types --- ...-accounts-oauth-consent-refactor-design.md | 88 ------------------- packages/astro/src/astro-components/index.ts | 1 + .../interactive/OAuthConsent.astro | 11 +++ .../mount-clerk-astro-js-components.ts | 1 + packages/astro/src/react/uiComponents.tsx | 11 +++ packages/astro/src/types.ts | 3 +- packages/clerk-js/sandbox/app.ts | 2 +- packages/clerk-js/src/core/clerk.ts | 6 +- packages/nextjs/src/client-boundary/hooks.ts | 1 + .../src/client-boundary/uiComponents.tsx | 5 +- packages/nextjs/src/index.ts | 2 + packages/nextjs/src/internal.ts | 6 ++ packages/nuxt/src/runtime/components/index.ts | 1 + packages/react/src/components/index.ts | 1 + .../react/src/components/uiComponents.tsx | 8 +- packages/react/src/hooks/index.ts | 1 + packages/react/src/internal.ts | 7 ++ packages/react/src/isomorphicClerk.ts | 14 +-- packages/shared/src/types/clerk.ts | 6 +- .../__tests__/OAuthConsent.test.tsx | 4 +- .../src/contexts/ClerkUIComponentsContext.tsx | 4 +- packages/ui/src/types.ts | 6 +- packages/vue/src/components/index.ts | 1 + .../components/ui-components/OAuthConsent.vue | 17 ++++ 24 files changed, 90 insertions(+), 117 deletions(-) delete mode 100644 docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md create mode 100644 packages/astro/src/astro-components/interactive/OAuthConsent.astro create mode 100644 packages/vue/src/components/ui-components/OAuthConsent.vue diff --git a/docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md b/docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md deleted file mode 100644 index 212aab20054..00000000000 --- a/docs/superpowers/specs/2026-04-14-accounts-oauth-consent-refactor-design.md +++ /dev/null @@ -1,88 +0,0 @@ -# Accounts Portal OAuth Consent Refactor Design - -> **For agentic workers:** This spec targets the accounts repo at `/Users/wobsoriano/Documents/projects/clerk/accounts`, not the javascript repo. - -**Goal:** Replace the accounts portal's manual OAuth consent implementation with the new `` component from `@clerk/nextjs/internal`, deleting all custom fetch utilities, hidden forms, and types in the process. - -**Context:** The `OAuthConsent` component (in `packages/ui`) now handles the full public path: it reads `client_id`, `redirect_uri`, and `scope` from the URL, fetches consent info via `clerk.oauthApplication.getConsentInfo`, renders scopes, and submits the consent form to `clerk.oauthApplication.buildConsentActionUrl`. The accounts portal's manual implementation duplicates all of this and can be deleted entirely. - ---- - -## Files Deleted - -- `components/oauth-consent/index.tsx` — manual fetch + `__internal_mountOAuthConsent` + hidden forms -- `utils/oauth-consent.ts` — `getConsentInfoForOAuth` FAPI fetch utility -- `types/OAuthConsent.ts` — `OAuthConsentInfo` type (only used by the above two files) - -## Files Modified - -### `types/index.ts` - -Remove the re-export of the deleted type file: - -```diff -- export * from './OAuthConsent'; - export * from './AccountPortalJSON'; - export * from './constants'; -``` - -`constants.ts` and `AccountPortalJSON.ts` are untouched — `DEV_BROWSER_JWT_MARKER` and `CLIENT_COOKIE_NAME` are still used elsewhere. - -### `pages/oauth-consent/[[...index]].tsx` - -Replace the entire file. `getServerSideProps` is removed — clerk-js handles `devBrowserJWT` and session auth automatically, and the new component reads all params from `window.location.search`. The referrer meta tag is kept (FAPI requires the `Origin` header on consent form POSTs). - -```tsx -import React from 'react'; -import Head from 'next/head'; -import { OAuthConsent } from '@clerk/nextjs/internal'; - -export default function ConsentPage(): JSX.Element { - return ( -
-
- - - - -
-
- ); -} -``` - -### `e2e/features/oauth-consent.test.ts` - -Error message text changes to match the new component's wording. Happy path assertion changes from hidden inputs (old hidden forms) to the Allow/Deny buttons the new component renders. - -| Old assertion | New assertion | -| --------------------------------------------------------- | ----------------------------------------- | -| `'Error: Authorization failed: The client ID is missing'` | `'The client ID is missing.'` | -| `'Error: Redirect URI not found'` | `'The redirect URI is missing.'` | -| `input[name="consented"][value="true"]` | `button[name="consented"][value="true"]` | -| `input[name="consented"][value="false"]` | `button[name="consented"][value="false"]` | - -### `e2e/unauthenticated/oauth-consent.test.ts` - -The old component returned an explicit `"Error: No session found"` div. The new component is wrapped with `withCoreUserGuard` which renders `null` for unauthenticated users. Update both tests to assert that the Allow button is not visible instead. - -```ts -// Before -await expect(page.getByText('Error: No session found')).toBeVisible(); - -// After -await expect(page.getByRole('button', { name: 'Allow' })).not.toBeVisible(); -``` - ---- - -## What Is Not Changing - -- `types/constants.ts` — stays, used by `utils/devBrowser.ts`, `utils/settings/environment.ts`, `utils/settings/accountPortal.ts` -- `utils/devBrowser.ts` — stays, unrelated to OAuth consent -- The page URL (`/oauth-consent`) and its Next.js route — unchanged -- The referrer meta tag — kept -- CSS class names (`pageContainer`, `componentContainer`) — unchanged 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 fe4da6a8e91..0f1098aefa0 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -51,7 +51,7 @@ import type { __internal_AttemptToEnableEnvironmentSettingResult, __internal_CheckoutProps, __internal_EnableOrganizationsPromptProps, - __internal_OAuthConsentProps, + OAuthConsentProps, __internal_PlanDetailsProps, __internal_SubscriptionDetailsProps, __internal_UserVerificationModalProps, @@ -1335,7 +1335,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, { @@ -1359,7 +1359,7 @@ 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 })); }; 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..b457fb1def1 100644 --- a/packages/nextjs/src/internal.ts +++ b/packages/nextjs/src/internal.ts @@ -3,5 +3,11 @@ * If you do, app router will break. */ export { MultisessionAppSupport } from './client-boundary/controlComponents'; +/** + * @deprecated Import `OAuthConsent` from `@clerk/nextjs` instead. + */ export { OAuthConsent } from './client-boundary/uiComponents'; +/** + * @deprecated Import `useOAuthConsent` from `@clerk/nextjs` instead. + */ export { useOAuthConsent } from '@clerk/shared/react'; 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/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/components/uiComponents.tsx b/packages/react/src/components/uiComponents.tsx index a87b83af675..ffaa9a744ef 100644 --- a/packages/react/src/components/uiComponents.tsx +++ b/packages/react/src/components/uiComponents.tsx @@ -1,5 +1,5 @@ import type { - __internal_OAuthConsentProps, + OAuthConsentProps, APIKeysProps, CreateOrganizationProps, GoogleOneTapProps, @@ -645,7 +645,7 @@ export const APIKeys = withClerk( ); export const OAuthConsent = withClerk( - ({ clerk, component, fallback, ...props }: WithClerkProp<__internal_OAuthConsentProps & FallbackProp>) => { + ({ clerk, component, fallback, ...props }: WithClerkProp) => { const mountingStatus = useWaitForComponentMount(component); const shouldShowFallback = mountingStatus === 'rendering' || !clerk.loaded; @@ -659,8 +659,8 @@ export const OAuthConsent = withClerk( {clerk.loaded && ( (); private premountPricingTableNodes = new Map(); private premountAPIKeysNodes = new Map(); - private premountOAuthConsentNodes = new Map(); + private premountOAuthConsentNodes = new Map(); private premountTaskChooseOrganizationNodes = new Map(); private premountTaskResetPasswordNodes = new Map(); private premountTaskSetupMFANodes = new Map(); @@ -747,7 +747,7 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { }); this.premountOAuthConsentNodes.forEach((props, node) => { - clerkjs.__internal_mountOAuthConsent(node, props); + clerkjs.mountOAuthConsent(node, props); }); this.premountTaskChooseOrganizationNodes.forEach((props, node) => { @@ -1282,17 +1282,17 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk { } }; - __internal_mountOAuthConsent = (node: HTMLDivElement, props?: __internal_OAuthConsentProps) => { + mountOAuthConsent = (node: HTMLDivElement, props?: OAuthConsentProps) => { if (this.clerkjs && this.loaded) { - this.clerkjs.__internal_mountOAuthConsent(node, props); + this.clerkjs.mountOAuthConsent(node, props); } else { this.premountOAuthConsentNodes.set(node, props); } }; - __internal_unmountOAuthConsent = (node: HTMLDivElement) => { + unmountOAuthConsent = (node: HTMLDivElement) => { if (this.clerkjs && this.loaded) { - this.clerkjs.__internal_unmountOAuthConsent(node); + this.clerkjs.unmountOAuthConsent(node); } else { this.premountOAuthConsentNodes.delete(node); } diff --git a/packages/shared/src/types/clerk.ts b/packages/shared/src/types/clerk.ts index f4ab6a08140..818975719d4 100644 --- a/packages/shared/src/types/clerk.ts +++ b/packages/shared/src/types/clerk.ts @@ -667,14 +667,14 @@ export interface Clerk { * @param targetNode - Target node to mount the OAuth consent component. * @param oauthConsentProps - OAuth consent configuration parameters. */ - __internal_mountOAuthConsent: (targetNode: HTMLDivElement, oauthConsentProps?: __internal_OAuthConsentProps) => void; + 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. */ - __internal_unmountOAuthConsent: (targetNode: HTMLDivElement) => void; + unmountOAuthConsent: (targetNode: HTMLDivElement) => void; /** * Mounts a TaskChooseOrganization component at the target element. @@ -2265,7 +2265,7 @@ export type __experimental_SubscriptionDetailsButtonProps = { }; }; -export type __internal_OAuthConsentProps = { +export type OAuthConsentProps = { /** * Customize the appearance of the component. */ 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(); + + + From c7c79fa076fa7dbc2d049847f62672fadae8dc39 Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Wed, 22 Apr 2026 11:07:00 -0700 Subject: [PATCH 3/4] chore: add changeset --- .changeset/fifty-grapes-ring.md | 12 ++++++++++++ packages/nextjs/src/internal.ts | 11 +++++++++-- packages/react-router/src/internal.ts | 14 +++++++++++++- packages/react/src/internal.ts | 10 ++++++++-- packages/tanstack-react-start/src/internal.ts | 14 +++++++++++++- 5 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 .changeset/fifty-grapes-ring.md diff --git a/.changeset/fifty-grapes-ring.md b/.changeset/fifty-grapes-ring.md new file mode 100644 index 00000000000..c4f0be0b40c --- /dev/null +++ b/.changeset/fifty-grapes-ring.md @@ -0,0 +1,12 @@ +--- +"@clerk/astro": minor +"@clerk/clerk-js": minor +"@clerk/nextjs": minor +"@clerk/nuxt": minor +"@clerk/react": minor +"@clerk/shared": minor +"@clerk/ui": minor +"@clerk/vue": minor +--- + +Move OAuthConsent component to public export diff --git a/packages/nextjs/src/internal.ts b/packages/nextjs/src/internal.ts index b457fb1def1..0e86e4ab0ff 100644 --- a/packages/nextjs/src/internal.ts +++ b/packages/nextjs/src/internal.ts @@ -2,12 +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'; + /** * @deprecated Import `OAuthConsent` from `@clerk/nextjs` instead. */ -export { OAuthConsent } from './client-boundary/uiComponents'; +const OAuthConsent = OAuthConsentOriginal; +export { OAuthConsent }; + /** * @deprecated Import `useOAuthConsent` from `@clerk/nextjs` instead. */ -export { useOAuthConsent } from '@clerk/shared/react'; +const useOAuthConsent = useOAuthConsentOriginal; +export { useOAuthConsent }; diff --git a/packages/react-router/src/internal.ts b/packages/react-router/src/internal.ts index 14f123a78ba..911b0872ef1 100644 --- a/packages/react-router/src/internal.ts +++ b/packages/react-router/src/internal.ts @@ -1 +1,13 @@ -export { useOAuthConsent, OAuthConsent } from '@clerk/react/internal'; +import { OAuthConsent as OAuthConsentOriginal, useOAuthConsent as useOAuthConsentOriginal } from '@clerk/react'; + +/** + * @deprecated Import `OAuthConsent` from `@clerk/react-router` instead. + */ +const OAuthConsent = OAuthConsentOriginal; +export { OAuthConsent }; + +/** + * @deprecated Import `useOAuthConsent` from `@clerk/react-router` instead. + */ +const useOAuthConsent = useOAuthConsentOriginal; +export { useOAuthConsent }; diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts index 57789bf4389..ffa4a4f466d 100644 --- a/packages/react/src/internal.ts +++ b/packages/react/src/internal.ts @@ -2,20 +2,26 @@ 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'; +import { useOAuthConsent as useOAuthConsentOriginal } from '@clerk/shared/react'; export { setErrorThrowerOptions } from './errors/errorThrower'; export { MultisessionAppSupport } from './components/controlComponents'; + /** * @deprecated Import `useOAuthConsent` from `@clerk/react` instead. */ -export { useOAuthConsent } from '@clerk/shared/react'; +const useOAuthConsent = useOAuthConsentOriginal; +export { useOAuthConsent }; /** * @deprecated Import `OAuthConsent` from `@clerk/react` instead. */ -export { OAuthConsent } from './components/uiComponents'; +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/tanstack-react-start/src/internal.ts b/packages/tanstack-react-start/src/internal.ts index 14f123a78ba..9f0bcbe8ffd 100644 --- a/packages/tanstack-react-start/src/internal.ts +++ b/packages/tanstack-react-start/src/internal.ts @@ -1 +1,13 @@ -export { useOAuthConsent, OAuthConsent } from '@clerk/react/internal'; +import { OAuthConsent as OAuthConsentOriginal, useOAuthConsent as useOAuthConsentOriginal } from '@clerk/react'; + +/** + * @deprecated Import `OAuthConsent` from `@clerk/tanstack-react-start` instead. + */ +const OAuthConsent = OAuthConsentOriginal; +export { OAuthConsent }; + +/** + * @deprecated Import `useOAuthConsent` from `@clerk/tanstack-react-start` instead. + */ +const useOAuthConsent = useOAuthConsentOriginal; +export { useOAuthConsent }; From 39afe25b8015d509a42cfe1b913774d442b6f38e Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Wed, 22 Apr 2026 11:25:50 -0700 Subject: [PATCH 4/4] chore: fix deprecation --- packages/react/src/internal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/internal.ts b/packages/react/src/internal.ts index ffa4a4f466d..399d3f14b98 100644 --- a/packages/react/src/internal.ts +++ b/packages/react/src/internal.ts @@ -1,3 +1,4 @@ +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'; @@ -5,7 +6,6 @@ import type React from 'react'; import { OAuthConsent as OAuthConsentOriginal } from './components/uiComponents'; import { ClerkProvider } from './contexts/ClerkProvider'; import type { ClerkProviderProps } from './types'; -import { useOAuthConsent as useOAuthConsentOriginal } from '@clerk/shared/react'; export { setErrorThrowerOptions } from './errors/errorThrower'; export { MultisessionAppSupport } from './components/controlComponents';