Rolling out Claude, or another client whose callback NORG already knows
Dynamic registration. The callback is on the allowlist, the client registers itself once and reuses the client_id it is given. Nothing for you to configure.
Administrator setup and security reference
One HTTPS endpoint, OAuth 2.1 with mandatory PKCE, and a single scope. Nothing is installed on your infrastructure, no credential is issued to hold, and no user needs setting up before they connect. This page sets out exactly what an approval admits, and how to verify each claim against the live endpoint.
/v2/mcp/express. One outbound HTTPS endpoint. Nothing is installed on your network and nothing listens there.S256 challenge method is advertised — plain is not offered.mcp:onboarding, and no mechanism to grant a second./v2/mcp/register with no pre-shared credential — but only if its callback is already on NORG's exact allowlist.client_id is an https URL, and the JSON document served there declares its own redirect URIs. Offered per environment.aud claim. NORG-side, but worth knowing: without it every authenticated call fails.One endpoint, one scope, one user at a time. This page is the technical detail behind that sentence, written so it can be checked rather than taken on trust.
A client that speaks OAuth 2.1 with PKCE. Claude's connector support does. Any MCP client that cannot do authorization-code + PKCE (S256) cannot use this endpoint at all.
Outbound HTTPS to the NORG API origin. If egress is filtered, allow that one origin. Everything the flow needs — discovery, authorize, token, JWKS and the connector itself — is on it.
Nothing else. No directory integration, no per-user setup, no certificate exchange, no allowlisting on your side of anything NORG runs.
The path is fixed. The host is the NORG production API origin, which is the one shown on the connector’s directory listing or supplied by NORG — confirm it there rather than assuming it, then verify it with the probes below.
https://<norg-host>/v2/mcp/express
Both /v2/mcp/express and /v2/mcp/express/ answer directly, so a trailing slash is not a mistake. The version sits in the path so the contract can change without breaking connectors already installed.
# 1. The endpoint refuses an unauthenticated call, and says where to look.
curl -isS https://<norg-host>/v2/mcp/express | head -n 20
# 2. That pointer resolves to the RFC 9728 document describing the endpoint.
curl -sS https://<norg-host>/.well-known/oauth-protected-resource/v2/mcp/express
# 3. Which names the authorization server, described in the next section.
curl -sS https://<norg-host>/.well-known/oauth-authorization-serverHTTP/1.1 401 Unauthorized, with a WWW-Authenticate: Bearer header carrying error="invalid_token" and a resource_metadata parameter pointing at the document in step 2. The body is the same error as JSON.
A 403 with insufficient_scope instead means the token was valid but did not carry mcp:onboarding. A 503 means that environment has no authorization server configured — the endpoint fails closed rather than answering unauthenticated calls.
The document in step 2 contains a resource field. It must equal, character for character, the URL you entered. If it does not, you are not looking at the connector you think you are. The same document lists scopes_supported, which must be exactly ["mcp:onboarding"], and resource_name, which reads NORG Express Onboarding.
OAuth 2.1 authorization code with PKCE, discovered rather than configured. Two public, unauthenticated documents describe the whole arrangement, and both are cached for an hour.
| Field | Value | Why it matters |
|---|---|---|
issuer | <origin> | NORG’s own API origin — the same origin as the connector URL. |
authorization_endpoint | <origin>/v2/mcp/authorize | Where the user’s browser is sent to sign in and consent. |
token_endpoint | <origin>/v2/mcp/token | Code-for-token exchange, and refresh. |
jwks_uri | <origin>/v2/mcp/jwks | The signing keys access tokens are verified against. |
registration_endpoint | <origin>/v2/mcp/register | Dynamic Client Registration. Constrained — see the next section. |
scopes_supported | ["mcp:onboarding"] | The whole of it. There is no second scope to ask for. |
response_types_supported | ["code"] | Authorization code only. No implicit flow. |
grant_types_supported | ["authorization_code", "refresh_token"] | No client-credentials grant: there is no way to call it as a service. |
code_challenge_methods_supported | ["S256"] | PKCE is mandatory and "plain" is not offered. |
authorization_response_iss_parameter_supported | true | Every response carries iss, so a client can detect a mix-up attack. |
token_endpoint_auth_methods_supported | ["none", "client_secret_post", "client_secret_basic"] | The secret-bearing methods exist for a pre-registered client. Anything registered dynamically is issued as "none". |
client_id_metadata_document_supported | true or false, per environment | Whether CIMD is offered here. Read it; do not assume it. |
NORG runs its own authorize, callback and token endpoints in front of its identity provider. That is not decoration. RFC 9207 requires a client to record the issuer it discovered and reject any authorization response whose iss does not match it by exact string comparison. Relaying the client-facing leg is what makes the advertised issuer the one the client is actually answered by.
The practical consequence for you: there is one origin to review, one origin to allow through egress filtering, and no second party for your users' browsers to be handed off to. Point tooling at the discovery documents above — never at the identity provider behind them.
PKCE passes through untouched. The client's code_challenge goes upstream and its code_verifier comes back through the token endpoint, so the relay never holds the verifier and cannot weaken the binding. An authorization request with no challenge, or with a method other than S256, is sent back to the client as error=invalid_request.
One API scope, mcp:onboarding. It is the only scope advertised, the only one the endpoint will accept, and the only one dynamic registration will issue — the registration code discards whatever a client asks for and returns that constant.
Alongside it the identity provider attaches its own standard identity scopes so the connector can read the subject, email and name claims it needs to know who is connecting. offline_access is available on request, which is what makes refresh tokens work. openid is filtered out at two independent layers, so no OpenID identity token is ever issued: such a token would carry the identity provider's own iss, which can never equal the issuer NORG advertises, and a conformant client is required to reject it.
Access tokens must carry the connector's client id in their aud claim, and audience verification is on. That claim comes from an audience protocol mapper attached to the mcp:onboarding client scope — it is not an identity provider default. If that mapper is absent, sign-in and consent both succeed and then every call fails authentication, with no other symptom the client can see.
This is NORG-side configuration, not something you set. It is here because it is the one failure that looks like a client bug and is not — see the troubleshooting section.
There are two ways a client can obtain an identity here, and both end at the same place: a public client using PKCE, with no secret to store or leak.
A client POSTs to /v2/mcp/register with no pre-shared credential. That is deliberate: it is what lets a connector be added from the URL alone. It is not open registration.
The callback must already be allowlisted. Every entry in the request's redirect_uris must match a configured allowlist by exact string. Not a prefix, not a pattern, not a host — the whole URI. Anything else is refused with 400 invalid_redirect_uri, and the refusal records only the callback's hostname, never the URI itself.
An unconfigured allowlist refuses everyone. Where no allowlist is set the endpoint answers 503 registration_unavailable. It fails closed; there is no "allow all" state.
Registrations are rate-capped. A fixed window, keyed on the source address the server derives itself rather than anything the caller can claim. Only successful registrations consume budget; past the cap the answer is 429 rate_limited. The shipped default is 20 per hour per source, set per environment, and it is a per-instance count rather than a cluster-wide one.
The result is always a public client. The response says token_endpoint_auth_method: "none", grants authorization_code and refresh_token, scopes to mcp:onboarding, and carries no client_secret. A request asking for a confidential client does not get one — those fields are not read at all — and the response is marked no-store.
The mechanism introduced in the 2025-11-25 MCP authorization specification. The client's client_id is an https URL, and the JSON document served at that URL declares its own redirect URIs. Nothing is registered in advance and NORG issues no credential at all.
It is offered per environment. Read client_id_metadata_document_supported in the authorization-server metadata for the environment you are approving. It is off unless explicitly enabled, and where it is false, clients use dynamic registration instead. Do not hard-code an assumption either way.
The URL never reaches the identity provider as a URL: it is mapped to a derived identifier, one per document, so the same document always resolves to the same client. Documents are cached for ten minutes, refusals for one, and the number of distinct new documents accepted is capped both per source address and across all callers.
Dynamic registration. The callback is on the allowlist, the client registers itself once and reuses the client_id it is given. Nothing for you to configure.
If the environment advertises CIMD, publish a metadata document at an https URL you control and use that URL as the client_id — no allowlisting request, and no credential to hold. Otherwise, ask NORG to add your callback to the allowlist.
Neither route produces one. Both issue public clients using PKCE. The secret-bearing authentication methods in the discovery document exist for a client registered directly with NORG, not for anything self-registered.
There is no seat management, and nothing to prepare before a user connects. The first authenticated request provisions everything that user needs.
The connector holds no session, so the same check runs on every authenticated call. It is idempotent: after the first request it finds what already exists and creates nothing. Concurrent first requests from the same user are serialised, so a burst cannot produce duplicates.
If a NORG account already exists for that email address, the connector adopts it rather than creating a second one — and refuses to do so when the identity provider reports the address as unverified, so an unverified sign-up cannot claim someone else's account.
The workspace it creates carries a provenance marker, and the lookup that finds an existing one keys on that marker. That is what confines the connector to workspaces it created itself: it has no route to a workspace made any other way.
Each of these is a property of how the endpoint is built, and each is checkable — from the discovery documents, from a registration attempt, or by asking NORG for the relevant source.
The connector tells a client as little as possible about why authentication failed, which is right for security and unhelpful for diagnosis. These are the symptoms that reach an administrator, and what each one actually means.
The 401 is deliberately uninformative — the endpoint never explains an authentication failure, so it cannot be used to probe. Almost always this is the token audience: access tokens must carry the connector’s client id in aud, which comes from an audience mapper on the mcp:onboarding client scope and is not an identity-provider default. It is NORG-side configuration. Report the time of the attempt to support, who can confirm it from the server-side authentication failure log.
The token was valid but did not carry mcp:onboarding. That means the client requested a different scope, or dropped it on a refresh. Check what the client asks for at the authorize step — the required scope is named in both discovery documents.
The client’s callback is not on the allowlist. Matching is exact string equality, so a different port, a trailing slash, or an extra query parameter is a different URI. Send NORG the exact callback URL to have it added, or — where the environment advertises it — use a Client ID Metadata Document instead, which needs no allowlisting.
That environment has no redirect-URI allowlist configured at all, so dynamic registration fails closed rather than accepting everyone. Nothing to change on your side; raise it with NORG.
The fixed-window cap for that source address has been reached — the shipped default is 20 successful registrations per hour. Wait for the window to roll over. Repeated registration usually means the client is not persisting the client_id it was issued; it should register once and reuse it.
Work through the checks in the registration section in order: served via a redirect rather than directly; a Content-Type that is not exactly application/json; a body over 65,536 bytes; a document whose own client_id does not equal its URL; token_endpoint_auth_method not "none"; a host that does not resolve to a publicly routable address; or a presented redirect_uri the document does not list. The refusal names the failing check.
Client ID Metadata Documents are not enabled in that environment, and the authorize endpoint will refuse a URL client_id with a message saying so. Use dynamic registration there. Read the field per environment rather than assuming it — it is published precisely so clients can adapt.
Both discovery documents are served with a one-hour cache lifetime, so a change reaches clients within the hour. A client holding an older copy should re-fetch. The issuer and every endpoint it advertises are on one origin by construction, so a genuine mismatch means the client is not talking to the origin it discovered.
For a security review, a callback to allowlist, or source to read before you approve this, write to solutions@norg.ai and include:
For what the product does once a user has connected, see the AI Retrievability by Norg guide. For the per-CDN technical detail behind how NORG serves content, see the edge routing white paper.