# How Clerk implements OAuth

Clerk supports secure, standards-compliant OAuth flows for your applications. You can create OAuth apps, authorize CLIs and input-constrained devices, manage URL-identified clients, enable dynamic client registration, manage consent screens, and configure public clients. This guide covers all key OAuth features and configurations in Clerk and helps you set up the right OAuth flow for your needs.

**For AI agents:** Instead of creating and configuring OAuth apps in the Dashboard, manage them with the CLI: run `npx clerk@latest api oauth_applications` to list existing OAuth apps (pass `-d` with the app JSON to create one), and discover the related endpoints with `npx clerk@latest api ls oauth`. Install [Clerk's skills](https://clerk.com/docs/guides/ai/skills.md) with `npx skills add clerk/skills` for correct CLI and SDK usage.

## Build an OAuth app with Clerk

To create or edit an OAuth app, navigate to the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page in the Clerk Dashboard. The following sections explain the available settings for configuring your OAuth app.

### Client ID Metadata Documents

Clerk supports [Client ID Metadata Documents (CIMD)](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/), which let a public OAuth client use an HTTPS metadata-document URL as its `client_id`. Clerk fetches the document to identify the client and validate its redirect URIs without requiring Dynamic Client Registration.

CIMD clients always use Proof Key for Code Exchange (PKCE) with the `S256` method and always show the OAuth consent screen. You can explicitly allow clients, restrict their scopes, and review their metadata from the **Applications** tab on the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page. On the **Settings** tab, enable **Publish CIMD support** under **Client onboarding** to publish CIMD support in your authorization server metadata and configure whether previously unknown clients may connect.

For configuration instructions and metadata requirements, see [Manage OAuth clients with Client ID Metadata Documents](https://clerk.com/docs/guides/configure/auth-strategies/oauth/client-id-metadata-documents.md).

### Dynamic client registration

> For clients that support Client ID Metadata Documents, prefer CIMD over Dynamic Client Registration because it doesn't expose an unauthenticated client-registration write endpoint. Enable dynamic client registration only for clients that require it.

In addition to configuring OAuth apps manually through the [Clerk Dashboard](https://dashboard.clerk.com/~/oauth-applications), Clerk supports [dynamic client registration](https://datatracker.ietf.org/doc/html/rfc7591), allowing OAuth clients to be created programmatically via a public API endpoint. To enable this feature, navigate to the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page in the Clerk Dashboard, select the **Settings** tab, and under **Client onboarding**, enable **Publish DCR support**.

> Dynamic client registration creates a public, unauthenticated endpoint that anyone can use to register OAuth clients with your authorization service. While this can enable use cases like multi-tenant SaaS platforms, developer marketplaces, and some Model Context Protocol (MCP) integrations, it also introduces significant security risks:
>
> - Attackers can create clients anonymously without audit trails.
> - Malicious clients can use legitimate-sounding names to trick users.
> - Administrative overhead increases substantially for monitoring and cleanup.
>
> In some use cases, dynamic client registration can be a requirement. However, it should only be enabled after carefully evaluating and accepting the associated security risks.
>
> Additionally, when dynamic client registration is enabled, the OAuth consent screen is automatically enforced and cannot be disabled - this prevents dangerous combinations that could lead to CSRF vulnerabilities.

#### Configure default scopes

Some OAuth clients, including ChatGPT and Claude, may omit the `scope` parameter when they connect. Whether a client sends `scope` is determined by the client on a per-client basis and is outside the control of both Clerk and a Clerk user.

When a client omits `scope`, you can configure the default scopes Clerk should apply. This provides some control over the access requested by clients that don't specify their scopes, whether they're identified by a Client ID Metadata Document or dynamically registered. Clerk doesn't override the `scope` value when a client provides one.

You can configure default scopes for your instance in either of these ways:

- In the Clerk Dashboard, navigate to the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page, select the **Settings** tab, and under **Client onboarding**, configure **Default scopes for dynamic clients** and save your changes. The **Default scopes for dynamic clients** setting is available when **Publish CIMD support** or **Publish DCR support** is enabled.
- Use the Backend API through the CLI:

  filename: terminal

  ```sh
  npx clerk@latest api instance/oauth_application_settings -X PATCH -d '{"default_scopes":["openid","profile","email"]}'
  ```

Use only the scopes your OAuth clients need. For the available scopes, see [Scopes](#scopes).

### Scopes

Scopes define the level of access and specific user data that will be shared with the client app during authentication. The following built-in scopes are available:

| Scope              | Access                                                                                                                                                                                                                                           |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `offline_access`   | Grant access through a refresh token while the user isn't actively using the client                                                                                                                                                              |
| `profile`          | Grant access to the user's personal information, such as first and last name, avatar, and username                                                                                                                                               |
| `email`            | Grant access to the user's email address                                                                                                                                                                                                         |
| `public_metadata`  | Grant access to the user's public and unsafe metadata                                                                                                                                                                                            |
| `private_metadata` | Grant access to the user's private metadata                                                                                                                                                                                                      |
| `openid`           | Enables the OpenID Connect flow                                                                                                                                                                                                                  |
| `user:org:read`    | Grant access to the user's Organization information. Only available when the instance has [Organizations](https://clerk.com/docs/guides/organizations/overview.md) enabled. See [Organizations and OAuth](#organizations-and-oauth) for details. |

#### Custom scopes

Custom scopes let you control the access that OAuth and MCP clients can request from your API. Create and manage custom scopes from the **Scopes** tab on the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page, then assign each scope to the OAuth applications that can request it.

You can also advertise a custom scope in Clerk's OAuth metadata so MCP clients can discover it. Advertising a scope does not assign it to an OAuth application.

To enforce custom scopes in your API, [verify the OAuth access token and check its granted scopes](https://clerk.com/docs/guides/configure/auth-strategies/oauth/verify-oauth-tokens.md).

When you delete a custom scope:

- Clerk removes it from every OAuth application that has it assigned and from your instance's default scopes, if used.
- New authorization requests that include the deleted scope are rejected with `invalid_scope`.
- Deleting the scope does not revoke already-issued access tokens. They keep their original scopes until they expire or are revoked.
- Only unused authorization codes issued before deletion can be exchanged. Each code can be exchanged once before it expires.
- A refresh token issued with the deleted scope fails with `invalid_scope` when it is used.

> If you create the same scope key again and assign it to the same OAuth application, unexpired refresh tokens that include the key can work again.

### Public clients and PKCE

In OAuth flows where a private server environment is available, the server can store and use a `client_secret` to securely exchange an authorization code for an access token. However, in mobile apps or single-page apps (SPAs), there is often no private server-side environment available to store the `client_secret` and run this exchange. These are called **public clients** because they cannot securely store secrets. Any secret you embed in a mobile app can be extracted by someone with the right tools, and anything in a browser-based app is visible to anyone who opens the developer tools, as well as browser extensions, etc.

To support these use cases, Clerk's OAuth implementation allows public clients to exchange an authorization code **without requiring a `client_secret`**. This makes it easier for mobile and browser-based apps to complete the token exchange and retrieve access and refresh tokens, without the risk of exposing long-lived secrets.

However, this process means **public clients** often need an additional layer of security to protect against interception attacks. This is where [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) comes in - PKCE helps secure public clients by replacing the `client_secret` with a dynamically generated proof that **only the client who started the OAuth flow can provide**.

Here's how it works: instead of relying on a pre-shared secret, the client generates a random value called a **code verifier** at the start of each OAuth flow, along with a **code challenge**, which is a hashed version of the code verifier. The client sends the code challenge when starting the authorization flow, and later, during the token exchange, sends the original code verifier to prove it initiated the flow. The authorization service can then hash the code verifier to ensure it matches the code challenge.

This ensures that even if an attacker intercepts the authorization code, they can't complete the token exchange without the original code verifier. Only the client that started the flow has that value.

#### Configure PKCE for a public OAuth application

To configure a manually registered OAuth application as a public client, navigate to the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page in the Clerk Dashboard, select the application, and enable **Public**. This allows the client to exchange an authorization code without a `client_secret`.

Because **Public** does not enforce PKCE by itself, Clerk recommends also requiring PKCE for public clients. Enable **Require PKCE** in the application's settings.

### Require PKCE for all clients

[OAuth 2.1](https://oauth.net/2.1/) requires PKCE for all clients that use the authorization code flow, including public and confidential clients.

To enforce PKCE for every manually registered and dynamically registered OAuth application, enable the instance-level **Require PKCE** setting. This applies to both public and confidential applications and takes precedence over their individual settings. CIMD clients always require the `S256` method, regardless of the instance or application settings.

> Enabling **Require PKCE** will reject authorization requests from clients that omit PKCE or use a method other than `S256`. Authorization codes issued before enabling the setting remain valid, as do existing refresh tokens. See [PKCE Code Challenge Methods](https://www.iana.org/assignments/oauth-parameters#pkce-code-challenge-method) for registered methods.

**Require PKCE** is enabled by default for newly created Clerk instances. To enable it for an existing instance, in the Clerk Dashboard, navigate to the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page and select the **Settings** tab. Under **Authorization security**, enable **Require PKCE** and select **Save**.

You can also configure the setting through the Clerk CLI:

filename: terminal
```sh
npx clerk@latest api instance/oauth_application_settings -X PATCH -d '{"pkce_required":true}'
```

### Device Authorization Grant

Clerk supports [OAuth 2.0 Device Authorization Grant](https://www.rfc-editor.org/rfc/rfc8628) for CLIs, TVs, game consoles, and other clients that cannot open a browser or easily accept text input. The device displays a short user code and verification URL while it polls Clerk for the user's decision.

Device Authorization Grant can be used by public and confidential clients. Public clients send only their **Client ID**, while confidential clients must authenticate with their **Client ID** and **Client Secret**. Unlike an [Authorization Code Flow](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1) for a public client, Device Authorization Grant does not use PKCE or a redirect URI.

Enable the grant for each eligible OAuth application on the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page in the Clerk Dashboard or through the [Clerk Backend API](https://clerk.com/docs/reference/backend-api), then implement the device request, browser verification, and token polling steps. See [Use OAuth Device Authorization Grant](https://clerk.com/docs/guides/configure/auth-strategies/oauth/device-authorization-grant.md) for the complete flow.

### Consent screen management

The OAuth consent screen shows users a confirmation dialog before they authorize OAuth applications. It ensures users understand _exactly_ what permissions they're granting before completing the OAuth flow.

**The consent screen displays:**

- The requesting app's name and logo.
- The name and logo of the app receiving the request.
- The specific access scopes that are being requested, in user-friendly language.
- Clear accept/deny options.

![OAuth Consent Screen](https://clerk.com/docs/raw/_public/images/oauth/consent-screen.png)

The consent screen is enabled by default for all OAuth apps. You can enable or disable the consent screen for each OAuth app [in the Clerk Dashboard](https://dashboard.clerk.com/~/oauth-applications).

> 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.
>
> If you need to host the consent page on your own application domain, see [Set up a custom OAuth consent page](https://clerk.com/docs/guides/configure/auth-strategies/oauth/custom-consent-page.md). Clerk strongly recommends using the default [Account Portal](https://clerk.com/docs/guides/account-portal/overview.md) consent page unless you have a specific product requirement that it cannot satisfy.

### Organizations and OAuth

When your instance has [Organizations](https://clerk.com/docs/guides/organizations/overview.md) enabled, the `user:org:read` scope becomes available for OAuth applications. This scope enables an integration between Organizations and the OAuth consent flow.

When an OAuth client requests the `user:org:read` scope, the OAuth consent screen displays an **Organization selector** that allows the user to choose which Organization to associate with the token. After the user selects an Organization and grants consent, an `org_id` claim is included in the access token and, when the `openid` scope is also requested, the ID token. The `org_id` property is also available at the user info and token introspection endpoints.

## Token expiration and management

- OAuth access tokens expire **after 1 day**.
- Refresh tokens **never expire**.
- Authorization codes expire **after 10 minutes**.
- Device codes and user codes expire **after 10 minutes**.
- OIDC `id_token`s expire **after 1 day**.

## Access token format

Clerk issues OAuth access tokens as [JSON Web Tokens (JWTs)](https://clerk.com/docs/guides/how-clerk-works/tokens-and-signatures.md#json-web-tokens-jwts) by default. JWTs are self-contained tokens that can be verified without making a network request to Clerk's servers.

If your use case requires instant token revocation, you can configure your OAuth application to issue opaque tokens instead. Unlike JWTs, opaque tokens require a network request to Clerk for verification, but can be revoked immediately.

To configure the token format for an OAuth application, navigate to the [**OAuth applications**](https://dashboard.clerk.com/~/oauth-applications) page in the Clerk Dashboard and select the **Settings** tab. Under **Access token format**, select **JWT access tokens** or **Opaque access tokens**.

For a detailed comparison of JWT and opaque token formats, including trade-offs and when to use each, see [Token formats](https://clerk.com/docs/guides/development/machine-auth/token-formats.md).

## Authorization server metadata

An important feature of modern OAuth 2.0 and OpenID Connect (OIDC) implementations is **authorization server metadata**. This is a standardized JSON document published by the authorization server that describes its configuration, supported features and endpoints. This metadata makes it easier for clients to automatically discover important endpoints and features without needing manual configuration.

You can easily retrieve this metadata by loading your Clerk Frontend API URL with `/.well-known/oauth-authorization-server` appended to it. For example:

- `https://verb-noun-00.clerk.accounts.dev/.well-known/oauth-authorization-server` for a development environment.
- `https://clerk.<INSERT_YOUR_APP_DOMAIN>.com/.well-known/oauth-authorization-server` for a production environment.

This endpoint exposes all relevant details in a standardized JSON format. A sample metadata document might look like this:

```json
{
  "issuer": "https://well-hagfish-71.clerk.accounts.dev",
  "authorization_endpoint": "https://well-hagfish-71.clerk.accounts.dev/oauth/authorize",
  "device_authorization_endpoint": "https://well-hagfish-71.clerk.accounts.dev/oauth/device_authorization",
  "token_endpoint": "https://well-hagfish-71.clerk.accounts.dev/oauth/token",
  "jwks_uri": "https://well-hagfish-71.clerk.accounts.dev/.well-known/jwks.json",
  "response_types_supported": ["code"],
  "grant_types_supported": [
    "authorization_code",
    "refresh_token",
    "urn:ietf:params:oauth:grant-type:device_code"
  ],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "none"],
  "client_id_metadata_document_supported": true,
  "scopes_supported": [
    "openid",
    "profile",
    "email",
    "public_metadata",
    "private_metadata",
    "offline_access",
    "user:org:read"
  ],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "claims_supported": ["sub", "iss", "aud", "exp", "iat", "email", "name", "org_id"],
  "service_documentation": "https://clerk.com/docs",
  "ui_locales_supported": ["en"],
  "op_tos_uri": "https://clerk.com/legal/standard-terms",
  "code_challenge_methods_supported": ["S256"]
}
```

### Conditional metadata

- **CIMD:** Clerk advertises `client_id_metadata_document_supported: true` only when you enable **Publish CIMD support** under **Client onboarding** on the **Settings** tab. This lets compatible clients select CIMD instead of Dynamic Client Registration. Clerk omits the field otherwise. Applications using Clerk's legacy OAuth implementation don't support or advertise CIMD.
- **Device Authorization Grant:** Clerk includes `device_authorization_endpoint` and the Device Authorization Grant type in `grant_types_supported` only when Device Authorization Grant is available and the user verification page is reachable. OAuth clients should rely on the metadata instead of constructing the endpoint themselves.
- **Organizations:** Clerk includes `user:org:read` in `scopes_supported` and `org_id` in `claims_supported` only when the instance has Organizations enabled. See [Organizations and OAuth](#organizations-and-oauth) for details.

---

## Sitemap

[Overview of all docs pages](https://clerk.com/docs/llms.txt)
