Skip to content

Commit 269a406

Browse files
wobsorianoSarahSoutoulalexisintechjescalanjfoshee
authored
Add OAuthConsent and useOAuthConsent docs (#3315)
Co-authored-by: Sarah Soutoul <sarah@clerk.dev> Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Co-authored-by: Jeff Escalante <jescalan@users.noreply.github.com> Co-authored-by: Jacob Foshee <jacob.foshee@clerk.dev>
1 parent d85d649 commit 269a406

16 files changed

Lines changed: 1334 additions & 7 deletions

File tree

docs/_partials/components/oauth-consent-custom-flow-examples.mdx

Lines changed: 435 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<If sdk="nextjs">
2+
```tsx {{ filename: 'app/oauth-consent/page.tsx' }}
3+
import { OAuthConsent, Show } from '@clerk/nextjs'
4+
import type { Metadata } from 'next'
5+
6+
export const metadata: Metadata = {
7+
referrer: 'strict-origin-when-cross-origin',
8+
}
9+
10+
export default function OAuthConsentPage() {
11+
return (
12+
<Show when="signed-in">
13+
<OAuthConsent />
14+
</Show>
15+
)
16+
}
17+
```
18+
</If>
19+
20+
<If sdk="react">
21+
```tsx {{ filename: 'src/OAuthConsentPage.tsx' }}
22+
import { OAuthConsent, Show } from '@clerk/react'
23+
24+
export function OAuthConsentPage() {
25+
return (
26+
<Show when="signed-in">
27+
<OAuthConsent />
28+
</Show>
29+
)
30+
}
31+
```
32+
33+
```html {{ filename: 'index.html' }}
34+
<meta name="referrer" content="strict-origin-when-cross-origin" />
35+
```
36+
</If>
37+
38+
<If sdk="react-router">
39+
```tsx {{ filename: 'app/routes/oauth-consent.tsx' }}
40+
import type { Route } from './+types/oauth-consent'
41+
import { OAuthConsent, Show } from '@clerk/react-router'
42+
43+
export const meta: Route.MetaFunction = () => [
44+
{
45+
name: 'referrer',
46+
content: 'strict-origin-when-cross-origin',
47+
},
48+
]
49+
50+
export default function OAuthConsentPage() {
51+
return (
52+
<Show when="signed-in">
53+
<OAuthConsent />
54+
</Show>
55+
)
56+
}
57+
```
58+
</If>
59+
60+
<If sdk="tanstack-react-start">
61+
```tsx {{ filename: 'src/routes/oauth-consent.tsx' }}
62+
import { OAuthConsent, Show } from '@clerk/tanstack-react-start'
63+
import { createFileRoute } from '@tanstack/react-router'
64+
65+
export const Route = createFileRoute('/oauth-consent')({
66+
head: () => ({
67+
meta: [
68+
{
69+
name: 'referrer',
70+
content: 'strict-origin-when-cross-origin',
71+
},
72+
],
73+
}),
74+
component: OAuthConsentPage,
75+
})
76+
77+
function OAuthConsentPage() {
78+
return (
79+
<Show when="signed-in">
80+
<OAuthConsent />
81+
</Show>
82+
)
83+
}
84+
```
85+
</If>
86+
87+
<If sdk="astro">
88+
```astro {{ filename: 'src/pages/oauth-consent.astro' }}
89+
---
90+
import { OAuthConsent, Show } from '@clerk/astro/components'
91+
---
92+
93+
<head>
94+
<meta name="referrer" content="strict-origin-when-cross-origin" />
95+
</head>
96+
97+
<Show when="signed-in">
98+
<OAuthConsent />
99+
</Show>
100+
```
101+
</If>
102+
103+
<If sdk="vue">
104+
```vue {{ filename: 'src/pages/oauth-consent.vue' }}
105+
<script setup lang="ts">
106+
import { OAuthConsent, Show } from '@clerk/vue'
107+
</script>
108+
109+
<template>
110+
<Show when="signed-in">
111+
<OAuthConsent />
112+
</Show>
113+
</template>
114+
```
115+
116+
```html {{ filename: 'index.html' }}
117+
<meta name="referrer" content="strict-origin-when-cross-origin" />
118+
```
119+
</If>
120+
121+
<If sdk="nuxt">
122+
```vue {{ filename: 'app/pages/oauth-consent.vue' }}
123+
<script setup lang="ts">
124+
// Components are automatically imported
125+
126+
useHead({
127+
meta: [{ name: 'referrer', content: 'strict-origin-when-cross-origin' }],
128+
})
129+
</script>
130+
131+
<template>
132+
<Show when="signed-in">
133+
<OAuthConsent />
134+
</Show>
135+
</template>
136+
```
137+
</If>

docs/_partials/hooks/hook-list.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
- [`useUser()`](/docs/reference/hooks/use-user)
22
- [`useClerk()`](/docs/reference/hooks/use-clerk)
33
- [`useAuth()`](/docs/reference/hooks/use-auth)
4+
- [`useOAuthConsent()`](/docs/reference/hooks/use-oauth-consent)
45
- [`useSignIn()`](/docs/reference/hooks/use-sign-in)
56
- [`useSignUp()`](/docs/reference/hooks/use-sign-up)
67
- [`useWaitlist()`](/docs/reference/hooks/use-waitlist)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
> [!IMPORTANT]
2+
> 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.

docs/guides/configure/auth-strategies/oauth/custom-consent-page.mdx

Lines changed: 178 additions & 0 deletions
Large diffs are not rendered by default.

docs/guides/configure/auth-strategies/oauth/how-clerk-implements-oauth.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ The consent screen is enabled by default for all OAuth apps. You can enable or d
8484

8585
> [!IMPORTANT]
8686
> Enabling the consent screen for all OAuth apps is **strongly recommended**. Without a consent screen, any logged-in user who visits an OAuth authorization URL automatically grants access to any requested scopes. The consent screen acts as a critical security checkpoint, preventing malicious apps from silently gaining access to user accounts.
87+
>
88+
> If you need to host the consent page on your own application domain, see [Set up a custom OAuth consent page](/docs/guides/configure/auth-strategies/oauth/custom-consent-page). Clerk strongly recommends using the default [Account Portal](/docs/guides/account-portal/overview) consent page unless you have a specific product requirement that it cannot satisfy.
8789
8890
### Organizations and OAuth {{ id: 'organizations-and-oauth' }}
8991

docs/guides/configure/auth-strategies/oauth/scoped-access.mdx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Before diving into implementations details, it's important to understand the dif
1414
- **Resource service (or Service Provider, SP)**: The service that holds the data that the [client](!oauth-client) wants to access. In this example, this would be **your own application** that uses Clerk for authentication and route protection.
1515

1616
> [!NOTE]
17-
> If you would like to know more about the terminology around OAuth, check out the [OAuth terminology guide](/docs/guides/configure/auth-strategies/oauth/overview#key-terminology).
17+
> If you're new to OAuth terminology, start with the [OAuth terminology guide](/docs/guides/configure/auth-strategies/oauth/overview#key-terminology).
1818
1919
This guide provides step-by-step instructions on how to build OAuth scoped access into a Clerk app.
2020

@@ -65,10 +65,12 @@ This guide provides step-by-step instructions on how to build OAuth scoped acces
6565

6666
Once this is complete, you'll be able to see the OAuth flow begin. If you are not currently signed in, you'll first be presented with a sign in screen. After signing in, Clerk will redirect to an OAuth consent screen, showing the requested scopes and asking for your consent.
6767

68-
> [!NOTE]
68+
> [!IMPORTANT]
6969
> The consent screen uses the scopes passed in the authorization request to inform the user exactly what they're granting access to, and to whom.
7070
>
7171
> By default, the consent screen is shown for all newly created OAuth apps, but this can be disabled in each app's settings [in the Clerk Dashboard](https://dashboard.clerk.com/~/oauth-applications), although not recommended. Learn more about [how Clerk's OAuth consent screen works](/docs/guides/configure/auth-strategies/oauth/how-clerk-implements-oauth#consent-screen-management).
72+
>
73+
> If you need to host the consent page on your own application domain, see [Set up a custom OAuth consent page](/docs/guides/configure/auth-strategies/oauth/custom-consent-page). Clerk strongly recommends using the default [Account Portal](/docs/guides/account-portal/overview) consent page unless you have a specific product requirement that it cannot satisfy.
7274
7375
Once you have accepted, you'll be redirected to the OAuth callback route, the `redirect_uri` specified earlier. This process will exchange the authorization code for an [access token](!oauth-access-token), and return the access token and refresh token as a JSON response, similar to this:
7476

docs/manifest.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,10 @@
361361
"title": "How Clerk implements OAuth",
362362
"href": "/docs/guides/configure/auth-strategies/oauth/how-clerk-implements-oauth"
363363
},
364+
{
365+
"title": "Set up a custom OAuth consent page",
366+
"href": "/docs/guides/configure/auth-strategies/oauth/custom-consent-page"
367+
},
364368
{
365369
"title": "Use OAuth for Single Sign-On (SSO)",
366370
"href": "/docs/guides/configure/auth-strategies/oauth/single-sign-on"
@@ -2318,6 +2322,10 @@
23182322
"title": "`useAuth()`",
23192323
"href": "/docs/reference/hooks/use-auth"
23202324
},
2325+
{
2326+
"title": "`useOAuthConsent()`",
2327+
"href": "/docs/reference/hooks/use-oauth-consent"
2328+
},
23212329
{
23222330
"title": "`useSignIn()`",
23232331
"href": "/docs/reference/hooks/use-sign-in"
@@ -2636,6 +2644,18 @@
26362644
"title": "Metadata types",
26372645
"href": "/docs/reference/types/metadata"
26382646
},
2647+
{
2648+
"title": "`OAuthApplication`",
2649+
"href": "/docs/reference/types/oauth-application"
2650+
},
2651+
{
2652+
"title": "`OAuthConsentInfo`",
2653+
"href": "/docs/reference/types/oauth-consent-info"
2654+
},
2655+
{
2656+
"title": "`OAuthConsentScope`",
2657+
"href": "/docs/reference/types/oauth-consent-scope"
2658+
},
26392659
{
26402660
"title": "`OrganizationCreationDefaults`",
26412661
"href": "/docs/reference/types/organization-creation-defaults"
@@ -3683,6 +3703,10 @@
36833703
"title": "`<GoogleOneTap />`",
36843704
"href": "/docs/reference/components/authentication/google-one-tap"
36853705
},
3706+
{
3707+
"title": "`<OAuthConsent />`",
3708+
"href": "/docs/reference/components/authentication/oauth-consent"
3709+
},
36863710
{
36873711
"title": "`<TaskChooseOrganization />`",
36883712
"href": "/docs/reference/components/authentication/task-choose-organization"
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
---
2+
title: '`<OAuthConsent />` component'
3+
description: Clerk's <OAuthConsent /> component renders an OAuth consent screen for authenticated users.
4+
sdk: astro, nextjs, nuxt, react, react-router, tanstack-react-start, vue, js-frontend
5+
---
6+
7+
The `<OAuthConsent />` component renders an OAuth consent screen for authenticated users after they are redirected to the OAuth authorization page. It retrieves the OAuth application's consent metadata and displays the requested scopes, allowing the user to approve or deny access.
8+
9+
By default, `<OAuthConsent />` reads the OAuth `client_id`, `scope`, and `redirect_uri` from the current URL. You can override the `client_id` and `scope` with props when rendering the component on a custom route.
10+
11+
For route setup guidance and security considerations, see [Set up a custom OAuth consent page](/docs/guides/configure/auth-strategies/oauth/custom-consent-page).
12+
13+
> [!IMPORTANT]
14+
> `<OAuthConsent />` only renders for authenticated users. If the user is signed out, the component will not be displayed.
15+
16+
<Include src="_partials/oauth-consent/callout" />
17+
18+
<If notSdk="js-frontend">
19+
## Example
20+
21+
The following example includes a basic implementation of the `<OAuthConsent />` component. You can use this as a starting point for your own implementation.
22+
23+
<Include src="_partials/components/oauth-consent-examples" />
24+
</If>
25+
26+
<If sdk="js-frontend">
27+
## Usage with JavaScript
28+
29+
Add the following `<meta>` tag to the page that hosts the OAuth consent screen:
30+
31+
```html {{ filename: 'index.html' }}
32+
<meta name="referrer" content="strict-origin-when-cross-origin" />
33+
```
34+
35+
The following methods available on an instance of the [`Clerk`](/docs/reference/objects/clerk) class are used to render and control the `<OAuthConsent />` component:
36+
37+
- [`mountOAuthConsent()`](#mount-o-auth-consent)
38+
- [`unmountOAuthConsent()`](#unmount-o-auth-consent)
39+
40+
The following examples assume that you have followed the [quickstart](/docs/js-frontend/getting-started/quickstart) in order to add Clerk to your JavaScript application.
41+
42+
### `mountOAuthConsent()`
43+
44+
Render the `<OAuthConsent />` component to an HTML `<div>` element.
45+
46+
```typescript
47+
function mountOAuthConsent(node: HTMLDivElement, props?: OAuthConsentProps): void
48+
```
49+
50+
#### `mountOAuthConsent()` params
51+
52+
<Properties>
53+
- `node`
54+
- [`HTMLDivElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement)
55+
56+
The container `<div>` element used to render the `<OAuthConsent />` component.
57+
58+
---
59+
60+
- `props?`
61+
- [`OAuthConsentProps`](#properties)
62+
63+
The properties to pass to the `<OAuthConsent />` component.
64+
</Properties>
65+
66+
#### `mountOAuthConsent()` usage
67+
68+
```js {{ filename: 'main.js', mark: [15] }}
69+
import { Clerk } from '@clerk/clerk-js'
70+
71+
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
72+
73+
const clerk = new Clerk(clerkPubKey)
74+
await clerk.load()
75+
76+
document.getElementById('app').innerHTML = `
77+
<div id="oauth-consent"></div>
78+
`
79+
80+
const oauthConsentDiv = document.getElementById('oauth-consent')
81+
82+
clerk.mountOAuthConsent(oauthConsentDiv)
83+
```
84+
85+
### `unmountOAuthConsent()`
86+
87+
Unmount and run cleanup on an existing `<OAuthConsent />` component instance.
88+
89+
```typescript
90+
function unmountOAuthConsent(node: HTMLDivElement): void
91+
```
92+
93+
#### `unmountOAuthConsent()` params
94+
95+
<Properties>
96+
- `node`
97+
- [`HTMLDivElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement)
98+
99+
The container `<div>` element with a rendered `<OAuthConsent />` component instance.
100+
</Properties>
101+
102+
#### `unmountOAuthConsent()` usage
103+
104+
```js {{ filename: 'main.js', mark: [19] }}
105+
import { Clerk } from '@clerk/clerk-js'
106+
107+
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
108+
109+
const clerk = new Clerk(clerkPubKey)
110+
await clerk.load()
111+
112+
document.getElementById('app').innerHTML = `
113+
<div id="oauth-consent"></div>
114+
`
115+
116+
const oauthConsentDiv = document.getElementById('oauth-consent')
117+
118+
clerk.mountOAuthConsent(oauthConsentDiv)
119+
120+
// ...
121+
122+
clerk.unmountOAuthConsent(oauthConsentDiv)
123+
```
124+
</If>
125+
126+
## Properties
127+
128+
All props are optional.
129+
130+
<Properties>
131+
- `appearance?`
132+
- <code>[Appearance](/docs/guides/customizing-clerk/appearance-prop/overview) | undefined</code>
133+
134+
An object to style your components. Will only affect [Clerk components](/docs/reference/components/overview) and not [Account Portal](/docs/guides/account-portal/overview) pages.
135+
136+
---
137+
138+
- `fallback?`
139+
- `ReactNode`
140+
141+
An element to be rendered while the component is mounting.
142+
143+
---
144+
145+
- `oauthClientId?`
146+
- `string`
147+
148+
Override the OAuth client ID. By default, Clerk reads this from the `client_id` query parameter in the current URL.
149+
150+
---
151+
152+
- `scope?`
153+
- `string`
154+
155+
Override the OAuth scope. By default, Clerk reads this from the `scope` query parameter in the current URL.
156+
</Properties>

docs/reference/components/overview.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Clerk offers a comprehensive suite of components designed to seamlessly integrat
1111
- [`<SignIn />`](/docs/reference/components/authentication/sign-in)
1212
- [`<SignUp />`](/docs/reference/components/authentication/sign-up)
1313
- [`<GoogleOneTap />`](/docs/reference/components/authentication/google-one-tap)
14+
- [`<OAuthConsent />`](/docs/reference/components/authentication/oauth-consent)
1415
- [`<TaskChooseOrganization />`](/docs/reference/components/authentication/task-choose-organization)
1516
- [`<TaskResetPassword />`](/docs/reference/components/authentication/task-reset-password)
1617
- [`<TaskSetupMFA />`](/docs/reference/components/authentication/task-setup-mfa)

0 commit comments

Comments
 (0)