Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/authorization/app-level-access-control.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ For [third-party applications](/integrate-logto/third-party-applications), app-l

If both are configured, the user must pass app-level access control before they can authorize the third-party application.

:::note
App-level access control applies to registered applications only. [Dynamic app](/integrate-logto/third-party-applications/dynamic-apps) clients have no application record, so they cannot be restricted this way. Their access is limited by the permissions you grant to the dynamic app and by user consent.
:::

## Relationship with Protected App \{#relationship-with-protected-app}

For [Protected App](/integrate-logto/protected-app), app-level access control restricts who can pass the Logto authentication layer and reach the protected origin server.
Expand Down
4 changes: 3 additions & 1 deletion docs/concepts/core-service/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,16 @@ In default values, `protocol` will be either `http` or `https` according to your

### OIDC provider SSRF protection {#oidc-provider-ssrf-protection}

Logto protects the OIDC provider's outbound requests against server-side request forgery (SSRF) by default. Requests to special-use addresses, including loopback and private network addresses, are blocked. This protection covers relying-party endpoints such as back-channel logout URIs, `jwks_uri`, and `sector_identifier_uri`.
Logto protects the OIDC provider's outbound requests against server-side request forgery (SSRF) by default. Requests to special-use addresses, including loopback and private network addresses, are blocked. This protection covers relying-party endpoints such as back-channel logout URIs, `jwks_uri`, and `sector_identifier_uri`, as well as the client ID metadata documents fetched for [dynamic app](/integrate-logto/third-party-applications/dynamic-apps).

If your self-hosted deployment intentionally needs to reach a trusted relying-party endpoint on a private network, set `OIDC_PROVIDER_SSRF_PROTECTION_DISABLED=true` and restart every Logto instance.

:::caution

This setting disables SSRF protection for all OIDC provider outbound requests, not just one endpoint. Only disable it when all configured relying-party endpoints are trusted and your network controls prevent access to sensitive internal services.

[Dynamic app](/integrate-logto/third-party-applications/dynamic-apps) cannot be enabled while this protection is off, since it fetches metadata documents from URLs provided by the clients themselves.

:::

### Enabling HTTPS {#enabling-https}
Expand Down
4 changes: 4 additions & 0 deletions docs/end-user-flows/consent-screen.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Similarly, in Logto, when Logto functions as the IdP, the consent screen is show

<img src="/img/assets/consent-screen-logto-as-idp.png" alt="Consent screen Logto as IdP" />

### Unregistered (dynamic) clients \{#unregistered-dynamic-clients}

If [dynamic app](/integrate-logto/third-party-applications/dynamic-apps) is enabled, clients can connect to your tenant without pre-registration. For these clients, the consent screen shows an additional notice, along with the host of the client ID URL. The client name and logo come from the client's own metadata document, so they can imitate any brand, while the host cannot be forged.

## How to configure the consent screen? \{#how-to-configure-the-consent-screen}

The Logto consent flow allows you to authorize logins from third-party applications. You can customize the branding and permission requests for each OIDC third-party application.
Expand Down
4 changes: 4 additions & 0 deletions docs/integrate-logto/application-data-structure.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ If you want to integrate your application with Logto, see [Integrate Logto](/int

_Application ID_ is a unique auto-generated key to identify your application in Logto, and is referenced as [client id](https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/) in OAuth 2.0.

:::note
[Dynamic app](/integrate-logto/third-party-applications/dynamic-apps) clients are not registered in Logto. Their client ID is a public HTTPS URL owned by the client, which serves the client metadata document.
:::

### Application types \{#application-types}

An _Application_ can be one of the following application types:
Expand Down
18 changes: 18 additions & 0 deletions docs/integrate-logto/third-party-applications/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ sidebar_position: 4
---

import AuthorizationIcon from '@site/src/assets/authorization.svg';
import CloudConnectionIcon from '@site/src/assets/cloud-connection.svg';
import CustomizationIcon from '@site/src/assets/customization.svg';
import TabItem from '@theme/TabItem';
import Tabs from '@theme/Tabs';
Expand All @@ -22,6 +23,13 @@ Logto is an identity service built on the [OpenID Connect (OIDC)](https://auth.w

Thus due to OIDC builds upon [OAuth 2.0](https://auth.wiki/oauth-2.0) adding an authentication layer, you can also integrate third-party app using OAuth protocol.

## Two ways to onboard a third-party app \{#two-ways-to-onboard-a-third-party-app}

- **Register the app in Logto** (this guide): you create the application and configure its permissions and redirect URIs. Use it when you know your partners.
- **[Dynamic app](/integrate-logto/third-party-applications/dynamic-apps)**: clients connect without pre-registration, using a public HTTPS URL that serves their own metadata document as the client ID. Use it when any client may connect, such as MCP clients and AI agents.

Both can be used at the same time.

## Create a third-party application in Logto \{#create-a-third-party-application-in-logto}

1. Go to <CloudLink to="/applications">Console > Applications</CloudLink>.
Expand Down Expand Up @@ -134,6 +142,16 @@ These requested permissions will be granted to the third-party applications only
icon: <CustomizationIcon width={20} height={20} />,
},
},
{
type: 'link',
label: 'Dynamic app (CIMD)',
href: '/integrate-logto/third-party-applications/dynamic-apps',
description:
'Allow OAuth clients to connect without pre-registration, using a client ID metadata document URL as their client ID.',
customProps: {
icon: <CloudConnectionIcon width={20} height={20} />,
},
},
]}
/>

Expand Down
99 changes: 99 additions & 0 deletions docs/integrate-logto/third-party-applications/dynamic-apps.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
description: Let OAuth clients connect to your tenant without pre-registration by using a client ID metadata document URL as their client ID.
sidebar_label: Dynamic app (CIMD)
sidebar_position: 3
---

# Dynamic app (CIMD)

Dynamic app allows OAuth clients to connect to your tenant without pre-registration. Instead of a client ID issued by Logto, the client uses a public HTTPS URL as its `client_id`. The URL serves a JSON document describing the client, called the [client ID metadata document (CIMD)](https://auth.wiki/client-id-metadata-document). Logto fetches the document and treats the client as a [third-party application](/integrate-logto/third-party-applications).

Dynamic app implements the IETF draft [OAuth Client ID Metadata Document](https://www.ietf.org/archive/id/draft-ietf-oauth-client-id-metadata-document-02.html).

## When to use dynamic app \{#when-to-use-dynamic-app}

Pre-registration works when you know your partners. It does not work when any client may connect, which is common in the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization/client-registration#client-id-metadata-documents) ecosystem: a user asks their AI agent to connect to your service, and the agent has never talked to your tenant before.

With dynamic app, the client publishes its own metadata at a URL it owns, and that URL is its identity. Nothing needs to be created in your tenant beforehand.

| | Registered third-party app | Dynamic app |
| ------------- | -------------------------- | ---------------------------------------- |
| Client ID | Issued by Logto | An HTTPS URL owned by the client |
| Registration | Required | Not required |
| Client secret | Supported | Not supported |
| Permissions | Per application | Shared by all dynamic clients |
| Grant types | Depends on app type | `authorization_code` and `refresh_token` |

Dynamic clients are public clients, so they always use [PKCE](https://auth.wiki/pkce). You can use both models at the same time. A partner you trust can still have a registered app with its own permissions.

## Enable dynamic app \{#enable-dynamic-app}

1. Go to <CloudLink to="/applications">Console > Applications</CloudLink> and open the **Third-party apps** tab.
2. Click **Create application** and select the **Dynamic app** card. It enables a tenant-level feature instead of creating an application.
3. Confirm in the dialog. Once enabled, any OAuth client with a valid public HTTPS client ID URL can start an authorization request for your tenant.
4. Open the dynamic app from the application list and go to the **Permissions** tab to grant permissions.

The dynamic app has no editable name, redirect URIs, or credentials. Each client provides its own in its metadata document.

:::note
Dynamic app requires the [OIDC provider SSRF protection](/concepts/core-service/configuration#oidc-provider-ssrf-protection), since Logto fetches metadata documents from the internet. Self-hosted instances that disable it cannot enable dynamic app.
:::

### Grant permissions \{#grant-permissions}

The **Permissions** tab defines the maximum permissions shared by all dynamic clients. It works like the [permission management](/integrate-logto/third-party-applications/permission-management) of a registered third-party app, with **User** and **Organization** sections.

Requesting a user permission that is not granted results in an error, while API resource and organization permissions that are not granted are ignored. Users also consent only to permissions they have through their [roles](/authorization/role-based-access-control).

Since every dynamic client shares this set, keep it minimal.

## Publish a client ID metadata document \{#publish-a-client-id-metadata-document}

If you are building a client that connects to Logto, host a metadata document and use its URL as your `client_id`. The URL must use the `https` scheme and contain no fragment, user info, or dot path segments. Logto sends a `GET` request to the URL and expects a JSON object.

For example, Claude Code uses `https://claude.ai/oauth/claude-code-client-metadata`, which serves:

```json
{
"client_id": "https://claude.ai/oauth/claude-code-client-metadata",
"client_name": "Claude Code",
"client_uri": "https://claude.ai",
"redirect_uris": ["http://localhost/callback", "http://127.0.0.1/callback"],
"token_endpoint_auth_method": "none"
}
```

The field names are the same as in [OAuth 2.0 Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591#section-2). Note that:

- `client_id` must be identical to the URL that serves the document.
- Dynamic clients are public clients. The document must not contain `client_secret`, and `token_endpoint_auth_method` must not be a shared-secret method. Use [PKCE](https://auth.wiki/pkce) instead.
- Metadata URIs such as `client_uri`, `logo_uri`, `tos_uri`, and `policy_uri` must be absolute `https` URLs. This does not apply to `redirect_uris`, so native clients can still use loopback addresses like the example above.
- `redirect_uris` are matched as exact strings, except that loopback addresses can be matched with any port. [Wildcard patterns](/integrate-logto/application-data-structure#wildcard-patterns) are also supported.
- `scope`, `grant_types`, and `response_types` are decided by Logto. If the document declares them, the values are ignored. Dynamic clients can only use the authorization code flow and refresh tokens.

Logto caches the document for up to 24 hours, following the `Cache-Control` and `Expires` headers of your response. Set them according to how often you expect to update the document.

## Consent screen \{#consent-screen}

Dynamic clients are third-party applications, so the [consent screen](/end-user-flows/consent-screen) is always shown.

The consent screen also shows a notice that the client is unregistered. The client name and logo come from the metadata document, so they can imitate any brand. The host of the client ID URL is displayed as well, since it is the only part the client cannot forge.

## Manage authorizations \{#manage-authorizations}

Authorizations granted to dynamic clients are regular third-party [grants](/sessions/grants-management). Users can review and revoke them in account settings, and admins can manage them through the Management API. The client ID URL is used to identify the client.

Disabling the dynamic app stops new authorization requests, while existing grants are kept. Revoking a grant requires the client to get user authorization again, but previously issued access tokens may remain valid until they expire.

## Limitations \{#limitations}

- Only the authorization code flow with PKCE and refresh tokens are supported. Client credentials, device flow, and token exchange are not available.
- Permissions and branding cannot be configured per client.
- [App-level access control](/authorization/app-level-access-control) does not apply to dynamic clients, since they have no application record.

## Related resources \{#related-resources}

<Url href="/integrate-logto/third-party-applications">Third-party app (OAuth / OIDC)</Url>
<Url href="/use-cases/ai/mcp-server-enable-third-party-ai-agent-access">
Enable third-party AI agent access to your MCP server
</Url>
4 changes: 3 additions & 1 deletion docs/sessions/grants-management.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ App grants represent user authorization state for specific client applications.

Use grants management when users or admins need to review authorized apps and revoke app access without revoking the whole Logto session.

When grants are revoked, previously issued opaque access tokens and refresh tokens for those grants are invalidated.
When grants are revoked, previously issued opaque access tokens and refresh tokens for those grants are invalidated. JWT access tokens are stateless, so previously issued ones remain valid until they expire.

## Choose the right path \{#choose-the-right-path}

Expand Down Expand Up @@ -44,6 +44,8 @@ Grant listing endpoints support optional query parameter `appType`:
- `appType=thirdParty`: List third-party app grants only.
- Omit `appType`: Return all active grants.

[Dynamic app](/integrate-logto/third-party-applications/dynamic-apps) clients are third-party applications, so their grants are returned with `appType=thirdParty`. The client ID URL is used as the application ID.

## Manage third-party app authorizations in Console \{#manage-third-party-app-authorizations-in-console}

In Logto Console, use the user details page to view and revoke authorized third-party apps.
Expand Down
23 changes: 23 additions & 0 deletions docs/use-cases/ai/fragments/_configure-third-party-ai-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ A **third-party app** is an application created by external developers (not the
To learn more, see [Third-party applications](/integrate-logto/third-party-applications).
:::

There are three ways to onboard AI agents:

- [Manually create the app in Console](#manually-create-a-third-party-app-in-logto), for testing or a few known agents.
- [Build a registration service on the Management API](#allow-developers-to-create-third-party-apps-in-logto), if you want to control who gets credentials.
- [Enable dynamic app](#let-any-ai-agent-connect-without-pre-registration), if any agent may connect and you don't want a registration step.

### Allow developers to create third-party apps in Logto \{#allow-developers-to-create-third-party-apps-in-logto}

If you are building a marketplace or want to allow developers to create third-party apps in Logto, you can leverage [Logto Management API](/integrate-logto/interact-with-management-api) to create third-party apps programmatically. This allows developers to register their applications and obtain the necessary credentials for authentication.
Expand All @@ -29,6 +35,23 @@ sequenceDiagram

Alternatively, you can manually create third-party apps in Logto Console to get familiar with the process.

### Let any AI agent connect without pre-registration \{#let-any-ai-agent-connect-without-pre-registration}

In an open MCP ecosystem, you usually don't know the agents in advance. [Dynamic app](/integrate-logto/third-party-applications/dynamic-apps) removes the registration step: the agent uses a public HTTPS URL serving its own client metadata document as its `client_id`, and Logto resolves it when the authorization request arrives.

```mermaid
sequenceDiagram
participant Agent as AI agent (MCP client)
participant Logto
participant Metadata as Agent's metadata document URL
Agent->>Logto: Authorization request with the client ID URL
Logto->>Metadata: Fetch the client ID metadata document
Metadata->>Logto: Client name, logo, redirect URIs, etc.
Logto->>Agent: Consent screen, then authorization code
```

You still control what agents can request through the permissions granted to the dynamic app, and every authorization goes through the user consent screen.

### Manually create a third-party app in Logto \{#manually-create-a-third-party-app-in-logto}

You can manually create a third-party app in Logto Console for testing purposes or ad-hoc integrations. This is useful when you want to quickly test the integration without implementing a full client-registration flow.
Expand Down
Loading