Connecting a hosted client that cannot hold a key
A bearer key is the simplest way to connect an agent, and it assumes something not every client can do: store a secret. Hosted connectors, browser-based clients, and anything a third party operates on your behalf often cannot. For those, the connection is OAuth, and the mental model shifts in one important way.
4 min read
Key or token: the actual difference
A key is an agent. It belongs to one identity, and every call it makes is that agent acting. Scope is decided when you create the key, and revoking it removes exactly that agent's access.
A token is you. The client is authorised to act as your account, within the scopes you approved. That is a different security shape and it produces the one wrinkle everybody hits, below.
Prefer a key for anything you deploy and control. Use OAuth where the client genuinely cannot store one, which is most hosted connectors, per the comparison in what an MCP email server is.
The flow, briefly
We are an OAuth 2.1 authorization server. A client discovers us at /.well-known/oauth-authorization-server, registers itself dynamically, and sends you here to approve what it is asking for. PKCE is required, and the token must be audienced to the MCP endpoint, so a token minted for something else will not work against it.
Dynamic registration being open is a deliberate choice: a hosted client cannot pre-register with every provider its users might connect. It is budgeted rather than unlimited, and registrations that are never authorised are cleaned up, so an unused client_id does not sit around indefinitely. Keep your client_id once you have one rather than registering on every start.
Scopes are coarse on purpose
Five: mail:read, mail:send, contacts, notes, and vault. Plus offline_access if the client needs to refresh.
Coarse scopes are easier to reason about at the moment of approval, which is when a person is actually deciding. A dialogue with twenty checkboxes gets approved without being read; five categories with plain meanings get looked at.
The one to be careful with is vault, because it reads credentials. Grant it only when the client genuinely needs an agent to sign into something, and understand what you are handing over, per permissions and grants.
| Scope | Lets the client |
|---|---|
mail:read | Read messages, threads, and search |
mail:send | Send, reply, and forward |
contacts | Read and write the workspace address book |
notes | Read and write granted notes |
vault | Read granted credentials, including TOTP codes |
offline_access | Refresh without sending you back to approve again |
The wrinkle: which agent is speaking
A token identifies you, not an agent. With one agent that is unambiguous, and the connection uses it. With several, the call has to say which one it is acting as, by sending an X-MCPmailer-Agent header carrying the handle.
Without it, the call is refused as ambiguous rather than guessed at. That refusal is deliberate: the answer decides which address a message appears to come from, and guessing wrong means a customer receives mail from your recruiting agent about their invoice.
POST /mcp HTTP/1.1
Authorization: Bearer <token>
X-MCPmailer-Agent: supportIf you are building a client, surface agent selection in your UI rather than picking one. If you are connecting one, expect to choose.
Revocation, and what it means
Revoke a connection from Connections in the dashboard and the app is cut off immediately; it has to ask again. That is the equivalent of revoking a key, with one difference worth internalising: revoking a connection removes an application's access to everything you granted it, while revoking a key removes one agent from everything.
Different axes, and both worth having. A quarterly look at connected applications belongs in the same review as your grants, per the security review questions an email agent should survive.
When not to use OAuth
If you are writing the agent and deploying it yourself, a key is simpler in every way: no refresh handling, no ambiguity about which agent is acting, and revocation that maps exactly to the thing you want to switch off. The rate limits are the same either way, and so is everything about quotas and the audit trail.
Reach for OAuth when the client is not yours to configure. That is the case it exists for.
Questions
- When should a client use OAuth instead of an API key?
- When it cannot store a secret: hosted connectors, browser clients, and third-party applications. Anything you deploy yourself should use a scoped key.
- What scopes are available?
mail:read,mail:send,contacts,notes,vault, andoffline_accessfor refresh. They are deliberately coarse so the approval screen is actually read.- Why does my call get refused as ambiguous?
- Because a token identifies you rather than one agent, and you have several. Send
X-MCPmailer-Agentwith the handle so the call resolves to one identity. - Do I need to register the client every time?
- No. Register once and keep the
client_id. Registrations that are never authorised are cleaned up, but a working client should reuse its id. - How do I revoke access?
- From Connections in the dashboard, which cuts the application off immediately. That removes an application's access; revoking a key removes one agent's.
- Is `vault` safe to grant?
- Only where the agent genuinely needs to sign into something, and only per secret. It reads credentials, so treat it as the scope that deserves a pause.
Give your agent an address it can answer from.
Create an inbox