Skip to main content

useOAuthConsent()

The useOAuthConsent() hook loads OAuth consent metadata for an authenticated user. You can use it to build a custom OAuth consent page that fetches the OAuth application's name, logo, URL, requested scopes, and related loading state.

Unlike the <OAuthConsent /> component, this hook doesn't read values from the current URL. Pass the oauthClientId explicitly. Optionally pass scope if you want Clerk to scope the request to a specific space-delimited scope string, and pass redirectUri when you need a public-suffix-aware redirectDomain for presenting the redirect destination.

Building a low-level custom consent flow is security-sensitive. For setup guidance, redirect URL presentation requirements, and a safer prebuilt component option, see Set up a custom OAuth consent page.

Important

Pages that host OAuth consent flows must set the referrer policy to strict-origin-when-cross-origin. This ensures the cross-origin POST request to FAPI includes the Origin header and Clerk can validate the CSRF token.

Parameters

useOAuthConsent() accepts a single object with the following properties:

  • Name
    enabled?
    Type
    boolean
    Description

    If true, a request will be triggered when the hook is mounted and the user is signed in. Defaults to true.

  • Name
    keepPreviousData?
    Type
    boolean
    Description

    If true, the previous data will be kept in the cache until new data is fetched. Defaults to true.

  • Name
    oauthClientId
    Type
    string
    Description

    The OAuth client_id from the authorize request. The hook is disabled when this value is empty or omitted.

  • Name
    redirectUri?
    Type
    string
    Description

    The redirect URI from the authorize request. When provided, the backend returns a PSL-resolved redirectDomain.

  • Name
    scope?
    Type
    string
    Description

    A space-delimited scope string from the authorize request.

  • Name
    data
    Type
    undefined | OAuthConsentInfo
    Description

    The OAuth consent screen metadata returned by Clerk, or undefined before the first successful fetch.

  • Name
    error
    Type
    null | ClerkAPIResponseError
    Description

    Any error that occurred during the data fetch, or null if no error occurred.

  • Name
    isFetching
    Type
    boolean
    Description

    Whether any request is still in flight, including background updates.

  • Name
    isLoading
    Type
    boolean
    Description

    Whether the initial consent metadata fetch is still in progress.

Example

The following example demonstrates how to use the useOAuthConsent() hook to fetch OAuth consent metadata and build a custom consent form. In this example, client_id and redirect_uri are read from the current URL and passed to the hook, and the form submits to the URL generated by the buildConsentActionUrl() method. The example intentionally focuses on the hook API; production consent pages must also clearly present the redirect destination and other security context described in Set up a custom OAuth consent page.

app/routes/oauth-consent.tsx
import type { Route } from './+types/oauth-consent'
import { useClerk, useOAuthConsent } from '@clerk/react-router'
import { useSearchParams } from 'react-router'

export const meta: Route.MetaFunction = () => [
  {
    name: 'referrer',
    content: 'strict-origin-when-cross-origin',
  },
]

export default function OAuthConsentPage() {
  const clerk = useClerk()
  const [params] = useSearchParams()
  const clientId = params.get('client_id') ?? ''
  const redirectUri = params.get('redirect_uri') ?? ''
  const scope = params.get('scope') ?? undefined

  const { data, isLoading, error } = useOAuthConsent({
    oauthClientId: clientId,
    scope,
    redirectUri,
  })

  if (!clientId) return <div>Missing OAuth client ID.</div>
  if (isLoading) return <div>Loading...</div>
  if (error || !data) return <div>Something went wrong.</div>

  const actionUrl = clerk.oauthApplication.buildConsentActionUrl({ clientId })

  return (
    <form method="POST" action={actionUrl}>
      <h1>{data.oauthApplicationName} wants access to your account</h1>
      <p>
        Redirect destination:{' '}
        <strong>{data.redirectDomain || new URL(redirectUri).hostname}</strong>
      </p>
      <ul>
        {data.scopes.map((scope) => (
          <li key={scope.scope}>{scope.description || scope.scope}</li>
        ))}
      </ul>

      <button type="submit" name="consented" value="false">
        Deny
      </button>
      <button type="submit" name="consented" value="true">
        Allow
      </button>

      {/* Forward the original OAuth parameters, except fields set by this form. */}
      {Array.from(params.entries())
        .filter(([key]) => key !== 'consented' && key !== 'organization_id')
        .map(([key, value], index) => (
          <input key={`${key}:${index}`} type="hidden" name={key} value={value} />
        ))}
    </form>
  )
}

Feedback

What did you think of this content?

Last updated on