Authorization is optional in the Model Context Protocol. What the spec says is narrower: if a server on an HTTP transport supports it, it should follow the MCP authorization spec, which is built on OAuth 2.1. A server on the stdio transport should not use that flow at all and should read credentials from its environment instead. That split explains most of what follows, including why Lumbox's local MCP server takes LUMBOX_API_KEY and its hosted server also runs an OAuth authorization server.
What an API key does badly
For one developer with one client, a key in a config file is fine. It gets awkward once people you do not control connect clients you did not build. Each person has to find a key in a dashboard and paste it into each client. The key is long-lived and usually has every permission the account has. Revoking it breaks every place it was pasted. And the server cannot tell Claude Desktop from Cursor from a script, because they all present the same string.
OAuth addresses those: the client registers itself, the user signs in and approves that specific client in a browser, and the client gets a short-lived access token plus a refresh token that can be revoked on its own. Scopes can narrow what was approved. How much that last part helps depends entirely on whether the server checks them, which comes up again below.
The flow the spec describes
- Challenge. The client calls the MCP server without a token and gets
401withWWW-Authenticate: Bearer resource_metadata="...". If there is no such header, the client tries the well-known URL instead. - Protected resource metadata (RFC 9728). That document names the server's
authorization_servers. MCP servers must publish it. - Authorization server metadata (RFC 8414, or OpenID Connect discovery). This gives the authorize, token and registration endpoints, and the supported PKCE methods.
- Registration. The client uses pre-registered credentials if it has them, then Client ID Metadata Documents if the server advertises them, then Dynamic Client Registration (RFC 7591) as a fallback. The current spec revision, 2026-07-28, formally deprecates DCR in favour of Client ID Metadata Documents, and keeps it working for backward compatibility.
- Authorization code with PKCE. Clients must use PKCE with
S256, and must refuse to continue if the authorization server's metadata lists nocode_challenge_methods_supported. - Resource indicators (RFC 8707). The client sends a
resourceparameter naming the MCP server in both the authorization and token requests. Servers must only accept tokens issued for them, and must not pass a client's token through to other APIs.
Around that sit the OAuth 2.1 basics: short-lived access tokens, rotating refresh tokens for public clients, redirect URIs that are HTTPS or localhost and matched exactly. The 2026-07-28 revision also asks authorization servers to return an iss parameter in the authorization response (RFC 9207), which clients must validate when present, and binds client credentials to the issuer that minted them.
What Lumbox implements
| Spec element | Lumbox today |
|---|---|
| Protected resource metadata | Yes. https://mcp.lumbox.co/.well-known/oauth-protected-resource names https://api.lumbox.co as the authorization server. |
| Authorization server metadata | Yes, at https://api.lumbox.co/.well-known/oauth-authorization-server, advertising S256 only. |
| Dynamic Client Registration | Yes, open, at POST /oauth/register. Public clients (token_endpoint_auth_method: "none") get no secret; others get one, shown once. |
| PKCE | Required. A request without code_challenge, or with any method other than S256, is refused. |
| Redirect URIs | Exact match against the registered list. HTTPS, http only on loopback, or a custom app scheme. |
| Codes and tokens | Authorization codes live 10 minutes and are single-use. Access tokens (oauth_at_...) live 1 hour. Refresh tokens (oauth_rt_...) live 30 days and rotate on every use. Revocation follows RFC 7009. |
The consent step works like this: /oauth/authorize checks the client, redirect URI and PKCE challenge, then sends the user to a consent page on the Lumbox dashboard, where they sign in and approve the client. Only after approval is a code minted.
Scopes and connecting a client
The scopes on offer are inboxes:read, inboxes:write, emails:read, emails:send, domains:write, credentials:read, credentials:write, browser and *, and a token never gets more than its client registered for. Leaving out emails:send keeps a client off the send, reply, forward and bulk endpoints, which is the line most people care about when they connect an assistant to a mailbox.
The hosted MCP server answers the initialize handshake and tools/list without a credential, so directories and clients can see the tool list before anyone signs in, and it names its protected resource metadata in a WWW-Authenticate header. Tool calls need a credential. If your client does not start the sign-in flow on its own, send Authorization: Bearer ak_... as a header instead; the MCP setup guide has the exact configuration for Claude Code and Cursor.
Authenticating agents, not humans
MCP's OAuth flow is delegated authorization: a person signs in once in a browser and the client acts for them afterwards. That fits an assistant like Claude or Cursor acting on a user's mailbox. It fits a headless worker less well, because there is nobody at a browser when it starts.
Lumbox's token endpoint supports the authorization_code and refresh_token grants and nothing else, so there is no machine-to-machine grant. An unattended agent has two options. It can hold a refresh token that a person obtained once, which works for up to 30 days at a time and rotates on each use, so the worker has to store the new one every time or it locks itself out. Or it can use an API key. For your own backend agents, a project-scoped key is usually the better choice: it is limited to one project's inboxes and refused on organization-level routes, so a leaked key reaches only that project.
So the practical split is OAuth for third-party clients that your users connect, and project keys for agents you run yourself. The key types and headers are covered on the authentication docs page, and the server's security posture more broadly on the security page.