Host A Client ID Metadata Document (CIMD)

On this page
Enterprise plan required

This feature requires an Enterprise plan.

Available since 1.70.0

This page shows how to publish a Client ID Metadata Document (CIMD) for an OAuth client you build, such as an MCP client or an AI agent. FusionAuth fetches the document the first time your client logs in and registers the client from it. For background, see OAuth Client Registration.

Before you start, the FusionAuth Tenant your client logs in to needs a CIMD domain that matches the origin of your document URL, or the * domain.

Publish The Document#

  1. Choose the URL for the document. This URL becomes your client's client_id. It must:

    • use https
    • have a path other than /, such as /oauth/client.json
    • contain no fragment or query parameters
    • be at most 2048 characters long
    • resolve to a public IP address. FusionAuth won't fetch from private, loopback or link-local addresses.
  2. Write the document. FusionAuth reads these fields:

    Field Required Description
    client_id Yes The document's own URL, exactly as your client sends it.
    client_name Yes The name users see on the consent screen.
    redirect_uris Yes At least one absolute redirect URI. Every entry must be valid, or FusionAuth rejects the whole document. Wildcards aren't allowed. Custom schemes, such as com.example.app:/callback, are allowed. For an http URI on a loopback IP address (127.0.0.1 or [::1]), FusionAuth accepts any port at login, as described in RFC 8252 Section 7.3. A localhost URI only works when the CIMD domain enables Allow localhost redirect URIs. When it does, FusionAuth also accepts any port for an http localhost URI.
    client_uri No A URL for your client's home page, shown on the consent screen.

    FusionAuth ignores every other field. Your client's scopes come from the MCP server's metadata, but must match the CIMD domain's allowed values. A scope value in the document has no effect: FusionAuth treats every CIMD client as a public client that uses PKCE, regardless of token_endpoint_auth_method.

    https://app.example.com/oauth/client.json
    {
      "client_id": "https://app.example.com/oauth/client.json",
      "client_name": "Example Agent",
      "client_uri": "https://app.example.com",
      "redirect_uris": [
        "https://app.example.com/oauth/callback",
        "http://127.0.0.1:3334/callback"
      ]
    }
    
  3. Serve the document at the URL. FusionAuth needs a 2xx response of at most 5KB. It waits up to 2 seconds to connect and 10 seconds for the response, and it doesn't follow redirects. FusionAuth doesn't check the content type, but application/json is a good choice. For more on how FusionAuth protects this fetch, see CIMD Security.

  4. Set a Cache-Control: max-age header to control how long FusionAuth caches the document. FusionAuth uses the smaller of your max-age and the domain's Maximum cache duration, and never caches for less than 15 minutes. Without a max-age, FusionAuth caches the document for 15 minutes. FusionAuth ignores the Expires header.

  5. Check the response:

    $ curl -i https://app.example.com/oauth/client.json
    

    You should get a 200 with no redirect, and the client_id in the body must match the URL you requested character for character. Even a trailing slash counts as a mismatch.

Log In With The Document#

Start the Authorization Code grant from your client with the document URL as the client_id:

  • Use the Tenant's endpoints, which end with the Tenant Id, such as https://<host>/oauth2/authorize/<tenantId> and https://<host>/oauth2/token/<tenantId>. You can find them in the Tenant's https://<host>/.well-known/openid-configuration/<tenantId> document, which reports "client_id_metadata_document_supported": true once CIMD is set up.
  • Send a PKCE code_challenge with the S256 method.
  • Send exactly one resource parameter on both the authorization request and the token request. For an MCP client, this is the URL of the MCP server. The value must be one of the CIMD domain's Authorized resource URIs. A refresh grant request can omit resource, and FusionAuth uses the one from the original grant.
  • Use a redirect_uri that appears in your document's redirect_uris exactly.

Update The Document#

FusionAuth keeps using its cached copy until it expires. The next login after that fetches the document again, so a change, such as a new redirect URI, takes effect at the first login after the cached copy expires. See CIMD Registration Caching And Lifecycle for how long that takes.

If that fetch fails, FusionAuth keeps using the old copy for the domain's Grace period. Refresh tokens your client already holds keep working even after the registration expires.

Troubleshooting#

When FusionAuth rejects a client, the user sees an invalid_client error page, and FusionAuth writes an Error entry to the Event Log under System -> Event Log . The entry includes the client's client_id URL, the requested resource, and a reason code: metadataRetrievalFailed when FusionAuth couldn't fetch or validate the document, lambdaRejected when the domain's registration lambda rejected the client, and rateLimited when the user registered too many new clients. A rate limited request also writes an Information entry. FusionAuth also sends a CIMD Registration Failed event.

The entry doesn't say which requirement the document failed, so check the document and the request against the requirements on this page. The most common causes of a rejected client are:

  • The client_id in the document doesn't exactly match the URL.
  • The URL redirects, for example from a path without a trailing slash to one with it.
  • The document's origin doesn't match a CIMD domain in the Tenant.
  • The redirect_uri on the request isn't listed in the document.
  • The request has no resource parameter, or more than one.
  • The resource isn't one of the CIMD domain's Authorized resource URIs.