Appearance
Sign in with OAuth
The hosted server at https://mcp.ohhai.app supports the MCP authorization flow (OAuth 2.1). You give your client the URL. It opens your browser. You sign in to OH HAI and click Approve. No token is shown, copied, or pasted.
What you do
- Add
https://mcp.ohhai.appas a server or connector in your client. - Your browser opens
https://inbox.ohhai.app/authorize. Sign in if you are not already. - The page says which app is asking, and that it will act as an agent on your account. Click Approve.
- You are sent back to the client. It is connected.
The client now appears on your Agents screen as an agent named after it (for example "Claude"). Revoke it there like any other agent. Its tokens stop working at once, and the next sign-in from that client creates a fresh agent.
Clients
| Client | How |
|---|---|
| Claude Desktop, claude.ai | Settings → Connectors → Add custom connector → paste the URL. |
| Claude Code | claude mcp add --transport http oh-hai https://mcp.ohhai.app then approve in the browser on first use. |
| Cursor, VS Code, Windsurf | Add the server with only url (serverUrl in Windsurf) and no headers; the client runs the sign-in on first use. |
| ChatGPT | Settings → Connectors → add the URL. |
A static bearer token still works everywhere it did before. OAuth is the path that needs no token handling; the token path is the fallback for a client that cannot open a browser. See Hosted server.
What happens underneath
The flow is the MCP authorization specification (revision 2026-07-28). Every step is standard, so any conformant client works without OH HAI-specific code.
- The client calls the server without a token and gets
401withWWW-Authenticate: Bearer resource_metadata="https://mcp.ohhai.app/.well-known/oauth-protected-resource". - It reads that document. It names the authorization server:
https://inbox.ohhai.app. - It reads
https://inbox.ohhai.app/.well-known/oauth-authorization-serverand learns the endpoints and rules below. - It identifies itself, either with a Client ID Metadata Document (an https URL as its
client_id, which the Hub fetches and validates) or by dynamic registration at the registration endpoint. Both are supported. Only public clients are registered; the Hub never issues a client secret. - It opens the browser at
https://inbox.ohhai.app/authorizewith a PKCE challenge (S256only), the exactredirect_uriit registered, andresource=https://mcp.ohhai.app. - You approve. The browser is sent back with a one-time
code, yourstate, andiss. - The client exchanges the code, the PKCE verifier, and the same
resourceat the token endpoint and receives an access token and a refresh token.
Endpoints
| Authorization server metadata | https://inbox.ohhai.app/.well-known/oauth-authorization-server |
| Protected resource metadata | https://mcp.ohhai.app/.well-known/oauth-protected-resource (also …/oauth-protected-resource/mcp) |
| Authorization | https://inbox.ohhai.app/authorize (a page in the web inbox) |
| Token | https://inbox.ohhai.app/auth/oauth2/token |
| Registration | https://inbox.ohhai.app/auth/oauth2/register |
| Revocation | https://inbox.ohhai.app/auth/oauth2/revoke |
Rules
- PKCE is required, method
S256. A request without a challenge is refused. resourceis required and must behttps://mcp.ohhai.app(orhttps://mcp.ohhai.app/mcp). The token is bound to that audience. The MCP server refuses a token issued for anything else, and a static token, which has no audience, keeps working.redirect_urimust match exactly what the client registered, with the one relaxation RFC 8252 §7.3 requires: for a loopbackhttpredirect the port may differ from the registered value, because a native client picks an ephemeral port at request time — nothing else may. An unknown client or an unregistered redirect never redirects anywhere; the page shows the error instead.- Access tokens live 1 hour. Refresh tokens live 30 days and rotate on every use. Presenting a used refresh token, or a used authorization code, revokes the whole connection: both the attacker and the real client have to sign in again.
- One agent per client per account. Re-approving the same client reuses the agent. Revoking the agent revokes the connection.
- No scopes in this version. A
scopevalue is accepted and echoed back. - A dynamic registration that never reaches an approval expires after 7 days. One that did is kept for as long as its connection exists.
- Revoking a refresh token at the revocation endpoint disconnects the whole connection, the same as revoking the agent.
- Redirect URIs may be
https, loopbackhttp(127.0.0.1,[::1],localhost), or a private app scheme. A loopback redirect shows an extra warning on the approval page, because any local process could be listening there.
Client ID Metadata Documents
If your client's client_id is an https URL with a path, the Hub fetches it, checks that the document's client_id equals that URL, and uses its client_name and redirect_uris. The fetch goes through the same protections as every outbound call the Hub makes: no private or loopback addresses, no redirects, a size and time limit. The document is cached for an hour. The approval page shows the URL, so you can see who is asking.