Skip to main content
MCP clients authorize against Langmail with standard OAuth 2.1 discovery — no pre-shared client IDs, no API keys. This page documents the flow as implemented, for anyone debugging a connection or building their own MCP client. The parties involved:
RoleURL
Resource server (the MCP server)https://mcp.langmail.me
Authorization server (Langmail’s identity service)https://auth.langmail.me
Login page (unauthenticated users land here)https://app.langmail.me/login

The flow

1

The first request gets a 401

A request to https://mcp.langmail.me/mcp without a bearer token returns 401 with a pointer to the resource metadata:
Response header
WWW-Authenticate: Bearer realm="mcp", resource_metadata="https://mcp.langmail.me/.well-known/oauth-protected-resource"
2

Discover the protected resource

Request
curl https://mcp.langmail.me/.well-known/oauth-protected-resource
Response
{
  "authorization_servers": ["https://mcp.langmail.me"],
  "bearer_methods_supported": ["header"],
  "resource": "https://mcp.langmail.me"
}
3

Discover the authorization server

Request
curl https://mcp.langmail.me/.well-known/oauth-authorization-server
Response
{
  "issuer": "https://mcp.langmail.me",
  "authorization_endpoint": "https://auth.langmail.me/api/auth/oauth2/authorize",
  "token_endpoint": "https://auth.langmail.me/api/auth/oauth2/token",
  "registration_endpoint": "https://auth.langmail.me/api/auth/oauth2/register",
  "userinfo_endpoint": "https://auth.langmail.me/api/auth/oauth2/userinfo",
  "scopes_supported": ["openid", "email", "offline_access"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"],
  "resource": "https://mcp.langmail.me"
}
The issuer is the MCP server’s own URL, while the functional endpoints live on auth.langmail.me. Clients only need to follow the endpoints in this document.
4

Register as a client

The registration endpoint accepts dynamic client registration (RFC 7591) without prior credentials, rate-limited per IP. MCP clients typically register as a public client with a loopback redirect:
Registration request
{
  "client_name": "My MCP client",
  "redirect_uris": ["http://127.0.0.1:33418/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none",
  "application_type": "native",
  "scope": "openid email offline_access"
}
Redirect URIs are matched exactly at authorization time, so register the precise URI you will use, including the port.
5

The user signs in and consents

The client opens the authorization URL with a PKCE challenge:
https://auth.langmail.me/api/auth/oauth2/authorize?response_type=code
  &client_id=<CLIENT_ID>
  &redirect_uri=http://127.0.0.1:33418/callback
  &scope=openid+email+offline_access
  &code_challenge=<S256_CHALLENGE>
  &code_challenge_method=S256
  &state=<STATE>
A user without a session is sent to the Langmail login page (Google sign-in) first. Then a consent screen shows what the named client is asking for; approving redirects back to the client’s redirect_uri with an authorization code. Every dynamically registered client goes through consent — there are no silent grants.
6

Exchange the code for tokens

Request
curl -X POST https://auth.langmail.me/api/auth/oauth2/token \
  -d grant_type=authorization_code \
  -d code=<CODE> \
  -d redirect_uri=http://127.0.0.1:33418/callback \
  -d client_id=<CLIENT_ID> \
  -d code_verifier=<PKCE_VERIFIER>
The response contains an access_token and, because offline_access was granted, a refresh_token. Public clients send no client secret; the PKCE verifier binds the exchange to the client that started the flow.
7

Call the MCP server

Request header
Authorization: Bearer <ACCESS_TOKEN>
The MCP server validates the token against the authorization server’s userinfo endpoint and resolves the caller to their @langmail.me mailbox. Every tool call then operates on that mailbox — tokens are per-user, and a token can never reach another user’s mail.

Tokens

  • Access tokens are opaque — treat them as bearer credentials, not as JWTs to inspect.
  • Refresh tokens are issued when offline_access is granted, so clients can stay connected without re-prompting you to sign in.
  • Ending access: remove the server from your MCP client — it discards its tokens, and without the refresh token access lapses. There is no dashboard for reviewing individual grants yet.

Requirements on the user

The signing-in Google account must belong to a Langmail user with an active @langmail.me mailbox. Accounts without one are rejected at the MCP server with 401 invalid_token — sign up at app.langmail.me first.
Authorization gives a client access to the tools the server exposes for your mailbox — currently read access to mail and read-write access to calendars. See the tool reference for the exact surface.