Skip to content
TDACorpIDENTITYSign in

Client ID metadata documents

Using an https address as your client_id instead of registering, what the document may and may not say, and how identity fetches it.

On this page

Status: In development, behind the oauth_cimd flag, which defaults OFF

. Off, an https address as a client_id is an unknown client, the same answer as for any identifier that was never registered. It follows the IETF draft Client ID Metadata Document, which is not a finished standard.

A registered client is created by an administrator and has an id that starts with tdaid_c_. A client ID metadata document (CIMD) skips that: your client_id is an https address, and the address serves a JSON document that describes the client. Identity fetches the document, checks it, and treats the result as a client for as long as the copy is fresh. It is meant for clients that cannot be registered in advance, such as a tool that any person may point at identity.

Because anyone who controls an address can publish a document, a document is a request, narrowed, never a grant. It cannot buy anything a registered client could buy beyond the limits below.

The address#

The client_id must be exactly the canonical form of an https address:

  • the scheme is https, with no user name or password, no fragment, no query and no port;
  • the path is not empty (a bare origin is refused);
  • the address equals its own normalised form, so no upper-case host, no dot segments and no explicit default port;
  • at most 512 characters.

An address that fails any of these is "not a valid client identifier", the same answer a malformed tdaid_c_ id gets.

The document#

Serve the document at the client_id address with the content type application/json, and a body no larger than the platform's cap (5,120 bytes by default, oauth.cimd.max_document_bytes). Its members are read by name and anything else is ignored:

MemberRule
client_idRequired. Must equal the address of the document.
redirect_urisRequired, 1 to 10 strings, held to the same rules as a registered client's redirect addresses. See Register a client.
client_nameOptional plain text, at most 200 characters, with no control or direction-override characters. If absent, the address's host is the name.
token_endpoint_auth_methodnone (the default) or private_key_jwt. No client secret: any client_secret* member refuses the document.
jwks or jwks_uriWith private_key_jwt, exactly one of them, holding 1 to 10 public keys, each with a kid, no duplicates. With none, neither. jwks_uri is fetched with the same guard as the document.
grant_typesOnly authorization_code and refresh_token.
response_typesOnly code.
scopeA space separated list from openid, profile, email and offline_access. Default openid profile email. The organization scope is not available.
application_typenative makes a native client; otherwise a private_key_jwt client is a web client and a none client is a single-page client.

What a document cannot change:

  • DPoP is always required. Every access token is bound to your key. See DPoP.
  • Subject identifiers are public. A CIMD client is never pairwise.
  • Lifetimes are fixed. Access tokens last 10 minutes and refresh tokens 30 days.
  • No organization. The client belongs to no product and to no organization, so the entry rule refuses it for every organization, and identity never offers it the session's organization. Its tokens carry no tid. See Installations and the entry rule.
  • It is a third-party client, so the person must consent. The consent screen shows the document's name and the address's host. Logo and other *_uri members are neither fetched nor stored.

The rest of the flow (pushed request, /authorize, /token) is the ordinary one, with your address as client_id.

How identity fetches it#

The fetch is where an unauthenticated caller can make identity send a request, so it is deliberately narrow:

  • https only, and only port 443.
  • Every address the host resolves to must be public, or the fetch is refused, and the connection is pinned to an address that was checked, so a second DNS answer cannot redirect it.
  • Redirects are not followed. A document that moves is a failed fetch.
  • One deadline covers the document, the key set and the DNS lookups: 2,000 ms by default (oauth.cimd.fetch_timeout_ms, 250 to 5,000).
  • The response must be a success with application/json, within the byte cap.
  • Concurrent requests for one address share one fetch, and a failure is remembered for 30 seconds, per process, so retry after that.

Freshness#

Identity keeps the validated copy until it expires, then fetches again. The lifetime is the document's own Cache-Control: max-age, capped at one hour by default (oauth.cimd.cache_ttl_s, 60 seconds to 24 hours) and never under 60 seconds; no-store and no-cache take the 60 second floor.

If a copy has expired and the document can no longer be fetched or no longer validates, the client is unknown: requests naming it fail, and refresh tokens it holds stop working. Keep the document reachable for as long as you want your tokens to work. A change to the document, such as a rotated key, takes effect at the next fetch, so keep the old key in jwks until the copy has expired.

When to register instead#

Register a client when you need something a document cannot carry: the client_credentials or token-exchange grants, scopes beyond the four above, pairwise subjects, or a product installation and so a named organization are. See Choosing an integration and Register a client.

Verified against commit c5ef357