OAuth redirect target that receives the authorization code
The OAuth redirect URI. The external authorization server sends the user’s browser here after they consent, so the request carries no Narrative bearer token.
This endpoint does not complete the connection. It stores the code against its flow
server-side and then redirects the browser (303) to the Narrative app, which finishes the job
by calling POST /mcp-connections/complete with the signed-in user’s own credentials.
You never call this directly — it’s the redirect_uri the browser is sent to.
Why it can’t complete the connection
Because it is public, anyone could reach it. If the callback also exchanged the code, someone
could start a flow of their own, get another user to open the resulting consent URL, and end up
with that user’s access token stored on their own connection. Splitting the flow removes
that: the state only lets you deposit a code, and exchanging one requires an authenticated
request from the user the flow belongs to.
The stored code is useless on its own — the exchange also needs the flow’s PKCE
code_verifier, which never leaves the server — and it is never included in the redirect URL.
Redirect parameters
The Location always points at the app’s callback page, with:
| Parameter | When |
|---|---|
state | Whenever the incoming state was well-formed. The app posts it back to complete the connection. |
error | Only on failure, see below. Absent means the code was stored and the app should complete. |
error values
| Value | Meaning |
|---|---|
access_denied | The user declined at the authorization server (RFC 6749 §4.1.2.1). |
invalid_request, unauthorized_client, unsupported_response_type, invalid_scope, server_error, temporarily_unavailable | Other authorization-server failures, per RFC 6749 §4.1.2.1. An unrecognized code is reported as server_error rather than echoed. |
invalid_state | The state was malformed. |
unknown_state | No authorization flow matches the state — it expired, or was already used. |
invalid_callback | Neither code nor error was present, or state was missing. |
Authentication
Public (no bearer). A state alone cannot produce a token — see above.
Query Parameters
The one-time state issued by POST /mcp-connections; identifies the authorization flow this
callback belongs to. Optional only so that a malformed callback still redirects the browser
to a page that can explain itself; in practice the authorization server always returns it.
The one-time authorization code issued by the external authorization server. Present on
success, mutually exclusive with error.
An RFC 6749 §4.1.2.1 error code, sent instead of code when the user declines or the
authorization server refuses.
Response
The browser is redirected to the Narrative app's callback page, which completes the
connection. Every outcome is reported this way — success, the user declining, an expired
state — with the details in the query parameters rather than in an error body.

