What your server must do
-
Return
401with a challenge for requests that have no valid token: -
Publish protected-resource metadata (RFC 9728). The document goes at
/.well-known/oauth-protected-resource, with your resource path appended when your endpoint is not at the root: -
Publish authorization-server metadata (RFC 8414) at
/.well-known/oauth-authorization-serveron the authorization server (/.well-known/openid-configurationis also read). Includeauthorization_endpoint,token_endpoint, andcode_challenge_methods_supported: ["S256"]. If you accept client ID metadata documents, setclient_id_metadata_document_supported: true. -
Validate every access token. Check the signature, issuer, expiry, and that the audience (
aud) is your MCP resource URL. Reject tokens minted for another resource. Return403withinsufficient_scopewhen a token lacks the scope a tool needs.
What Allternit does
When a user connects your server, Allternit runs the authorization-code flow with PKCE:-
Discovery. It fetches
/.well-known/oauth-protected-resourceon your server’s origin and takes the first entry ofauthorization_servers. If that document is missing, it uses your server’s origin as the authorization server. It then reads/.well-known/oauth-authorization-server(then/.well-known/openid-configuration) on that issuer forauthorization_endpointandtoken_endpoint. If neither is found, it falls back to<issuer>/authorize, and to token-endpoint discovery under your MCP server URL (/.well-known/oauth-authorization-server, then/oauth/token,/token,/v1/token). -
Authorization request. It redirects the user’s browser to your
authorization_endpointwith these query parameters: -
Callback. Your authorization server redirects back with
codeandstate. Allternit exchanges the code at thetoken_endpointfrom your authorization-server metadata (grant_type=authorization_code,code,code_verifier,redirect_uri,resource,state, andclient_id), then stores the tokens encrypted. When an access token expires, Allternit uses your refresh token at the same endpoint, again withresource. Tokens are used only in anAuthorization: Bearerheader on requests to your server, and are never logged or returned to the browser.
client_id_metadata_document_supported and the connecting Allternit instance has a public HTTPS address your server can fetch the document from), then dynamic client registration (when your metadata has a registration_endpoint). If none applies, the connect step fails with a message saying so.
Every fetch Allternit makes during discovery refuses private, loopback, and link-local addresses.
Allternit does not send a
scope parameter in the authorization request. Configure your authorization server to grant your default scopes when none are requested, and advertise them in scopes_supported.Client ID metadata documents
Allternit identifies itself with a client ID metadata document (CIMD). Theclient_id is the URL of a JSON document Allternit hosts, so your authorization server does not need to register Allternit ahead of time.
The document is served by the Allternit API at /oauth/client.json. A connection made from Allternit Desktop runs on the user’s own computer (http://127.0.0.1:8013), where your authorization server can’t fetch the document, so Desktop uses dynamic client registration instead, with a loopback redirect_uri. If your server offers client ID metadata documents but no registration_endpoint, Desktop users can’t connect it unless the connector has a client ID configured.
The hosted document:
- sets
client_id_metadata_document_supported: truein its metadata, - fetches the
client_idURL when it sees one, - checks that the
redirect_uriin the request is listed inredirect_uris, - treats the client as a public client (
token_endpoint_auth_method: none) and requires PKCE.
Dynamic client registration
If your authorization server advertises aregistration_endpoint, Allternit registers itself there (RFC 7591) the first time a user connects, unless the connector already has a client ID or your server supports CIMD. The request is a JSON POST with:
client_id. If you return a client_secret and a token_endpoint_auth_method of client_secret_basic or client_secret_post, Allternit stores the secret encrypted and uses that method. The registration is stored on that user’s connector, so every user gets their own client, and it is reused for later connects and token refreshes. If your token endpoint answers invalid_client, Allternit discards a client it registered and registers again on the next connect. A client ID configured on the connector is never discarded. The registration endpoint must be an https URL on a public host, like the other discovery endpoints, and Allternit does not follow redirects.
Redirect URI
Register theredirect_uri from the CIMD document with your authorization server if it needs an allowlist. It is the Allternit API’s /mcp/oauth/callback.
How users connect
- The user adds your server (from a plugin package or a directory listing) as a connector.
- Allternit creates the connector for your server URL and starts the flow above.
- The user signs in and approves access on your authorization server.
- Allternit stores the token. From then on, tool calls to your server carry it.
Permission prompts
Every installed app has a permission mode. It decides when Allternit asks the user before running one of your tools:
The decision comes from your tool annotations, so accurate annotations matter. See annotations. A tool with no
readOnlyHint is treated as a change.
The host enforces the install’s permission mode on tool calls your View makes, using the annotations from your server’s own
tools/list. A tool it cannot find is treated as destructive. The same mode applies to tool calls the model makes during a chat turn: Allternit asks the user before each call your annotations mark as needing confirmation, and a declined call fails with “The user declined this tool call”. Expect users to change the mode.x-allternit/* extensions that write data or start work show a confirmation prompt drawn by the host over the View. The View cannot skip or answer it.
Testing your OAuth setup
- Fetch your two metadata documents with
curland confirmresourcematches your MCP URL exactly. - Call your endpoint with no token and confirm you get
401with aresource_metadataparameter. - Run the flow with a tool such as the MCP Inspector before you connect it in Allternit.
- After connecting, call a tool and check that your server sees a token whose
audis your resource URL.