Agent door
Authentication
The door admits an agent two ways: a person signs in from an AI assistant and approves a consent screen, or the agent presents an identity assertion from a trusted issuer. Either way it gets an org-scoped, capability-bound session.
The door does not invent its own auth. It uses standards-based OAuth discovery and two
grants: the OAuth authorization-code flow, for a
person connecting an AI assistant by signing in, and the
ID-JAG identity-assertion grant, for provisioned
access. Provisioned sessions can add DPoP
proof-of-possession. The base host is https://api.yellowhead.digital.
Discovery
Anonymously-fetchable metadata documents describe the door:
| Document | Endpoint |
|---|---|
| Protected-resource metadata (RFC 9728) | GET /.well-known/oauth-protected-resource |
Protected-resource metadata for the /mcp resource (RFC 9728, path-suffixed form) | GET /.well-known/oauth-protected-resource/mcp |
| Authorization-server metadata (RFC 8414) | GET /.well-known/oauth-authorization-server |
The two protected-resource documents are the same document. The authorization-server document advertises both grants. For provisioned access, it lists the identity-assertion grant type and profile and the DPoP signing algorithms the token endpoint accepts:
- Grant type:
urn:ietf:params:oauth:grant-type:jwt-bearer - Identity-assertion profile:
urn:ietf:params:oauth:grant-profile:id-jag - Assertion type:
urn:ietf:params:oauth:token-type:id-jag - Token endpoint:
POST /mcp/oauth/token - Token-endpoint client auth:
none(the assertion, and optionally a DPoP proof, are the credential) - DPoP signing algorithms:
RS256,PS256,ES256,ES384,EdDSA
Sign-in: the authorization-code flow
A person connects an AI assistant by adding https://api.yellowhead.digital/mcp as
a custom connector in an MCP client that supports OAuth sign-in, such as Claude or ChatGPT.
The client finds the endpoints from the discovery documents above, sends the person to
app.yellowhead.digital to sign in, and shows a consent screen that lists what the
connection will be able to do. When the person approves, the client exchanges the returned
code at the token endpoint for an access token and a refresh token. It works on every plan,
Free included. The sign-in can wait until it is needed: a request with no credential may run
initialize, tools/list and the one public tool,
describe_yellowhead, and a call to any other tool gets HTTP 401 with a
WWW-Authenticate challenge (error="invalid_token" and the
resource_metadata URL), which is the client's cue to sign the person in. For step-by-step setup in a specific assistant, see
Connect Claude and
Connect ChatGPT.
For this flow, the authorization-server document also advertises:
- Authorization endpoint:
https://app.yellowhead.digital/oauth/authorize - Grant types:
authorization_codeandrefresh_token - Response type:
code, returned in the query, with anissparameter on every authorization response (RFC 9207) - PKCE:
S256only - Client registration: a client ID metadata document (the client's ID is a URL), or dynamic registration at
POST /mcp/oauth/register - Client auth:
none(every client is public) - Scopes:
readandoffline_access - Revocation endpoint:
POST /mcp/oauth/revoke
Scopes never widen what a connection can do. Its capabilities come from the account's plan:
the read capabilities that plan can use, and diagnostic.start, which starts a
Diagnostic: the first call returns a preview, and only a second call with the preview's
single-use confirmation token starts the run, using only the account's included monthly
Diagnostics. Depending on the plan, it can also file the run in a workspace or, for an owner or
admin of an Agency team account, create a new prospect or client workspace (see
Capabilities). A sign-in connection holds no
action-item write capability. It can do only what the
person can do in the account, owners and admins of a team account can turn members'
connections off, and the person sees and removes their connections in
Settings › AI assistants.
The access token is the same opaque session token the provisioned path issues (prefix
yh_mcp_). Each refresh token is used once: every refresh returns a new one, and
presenting an old one again ends the connection, so the person connects again.
ID-JAG: the identity assertion
An agent authenticates by presenting an ID-JAG — a signed JWT issued by an identity provider your workspace has registered as a trusted issuer. The token endpoint verifies the assertion end to end: its type, signing algorithm, signature (against the issuer's published keys), audience, expiry, and required claims, and that the asserted subject and client are permitted by a live grant in your workspace.
A single assertion mints a single session — its unique identifier is consumed on use, so an
assertion cannot be replayed. A new session needs a fresh assertion. Where more than one
grant could match an assertion, the client selects one by passing a grant_id.
Request
POST /mcp/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=<the ID-JAG>
&grant_id=<optional grant selector> Response
{
"access_token": "yh_mcp_...",
"token_type": "Bearer", // "DPoP" when the session is key-bound
"expires_in": 3600,
"scope": "diagnostic.read report.read ..." // the grant's capabilities
}
The access token is an opaque session token (prefix yh_mcp_),
not a JWT. Every request re-checks the session row and the grant behind it, so revoking a
grant or a session takes effect within about a minute — see below.
Calling the door
Present the session token as a bearer credential on every MCP transport request:
POST /mcp
Authorization: Bearer yh_mcp_...
Content-Type: application/json
MCP-Protocol-Version: 2025-06-18
{ "jsonrpc": "2.0", "method": "tools/list", "id": 1 } POST /mcp carries the JSON-RPC calls (initialize,
tools/list, tools/call). DELETE /mcp ends a protocol
session. Tool results return as JSON in the POST response body; the door does not open a
server-sent event stream.
DPoP: sender-constraining (optional, sometimes required)
A bearer session token is, on its own, a bearer credential: whoever holds it can use it.
DPoP (RFC 9449) closes that gap by binding the session to a key the client
proves it holds. When a client presents a valid DPoP proof at the token endpoint, the
session is bound to that key's thumbprint (a binding that can never be changed afterward)
and the response returns token_type: DPoP. A key-bound session must then
present a fresh proof — signed by the same key, over this exact request and this exact
token — on every transport request.
DPoP is optional by default and required per grant: a workspace can mark a grant so that only an issuer-confirmed, key-bound session is admitted — which is the posture for every external-customer grant. DPoP is also the prerequisite for the direct-apply write path (see Write approvals): without a proven key binding, writes are always held for a human.
Sessions, revocation, and expiry
- Lifetime. A provisioned session lives until
expires_inelapses (the grant's configured TTL, default one hour) or it is terminated early. - No refresh on provisioned access. The ID-JAG grant issues no refresh token; a new session needs a fresh identity assertion. A sign-in connection refreshes with its refresh token, as described above.
- Revocation lands within ~60 seconds. Revoking the grant, revoking the trusted issuer (which kills every session under it), or narrowing the grant's allowed subjects terminates a live session on its next revalidation. Deleting the session row is immediate.
- Redeploys. A backend redeploy clears in-memory protocol sessions; the
bearer session survives in the database, so the client re-runs
initializewith the same token and continues.