DocsAuthentication

Authentication

Two ways in: a bearer API key for developer tools, or OAuth 2.1 for connector clients like Claude and ChatGPT. Both resolve to the same workspace identity.

API keys

Keys look like glm_live_… and go in the standard header. Mint them at Settings, MCP; only a SHA-256 hash is stored, so the raw value is shown exactly once.

header
Authorization: Bearer glm_live_YOUR_KEY
  • Up to 10 active keys per workspace.
  • Each key records its own last-used timestamp, so you can tell which client is live.
  • Revoking takes effect on the next call, not at some expiry.

Scopes

ScopeGrantsUse it for
getlead:readSearch, lists, campaign stats, inbox reads, CRM reads, exports.Research chats, scheduled jobs, anything unattended.
getlead:writeCreate lists and campaigns, start verification, send replies, update CRM, suppress addresses.Interactive sessions where you approve sends.
Two keys beats one
Mint a read-only key for anything on a timer and a write key for hands-on work. A read-only credential cannot send email even if the model decides it should.

OAuth 2.1

Connector clients cannot paste headers, so the server is also an OAuth 2.1 resource server with its own authorization server at https://mcp.getle.ad. The flow:

  1. The client registers itself with dynamic client registration (RFC 7591) at /mcp/oauth/register. Redirect URIs are allowlisted; loopback is permitted for desktop clients.
  2. It sends the user to /mcp/oauth/authorize with PKCE (S256 only) and a resource parameter.
  3. Getlead shows a consent screen. The user signs in with their normal account and approves the scopes.
  4. The client exchanges the code at /mcp/oauth/token. Codes are single use with a short TTL; replay returns invalid_grant.
  5. The access token is a JWT bound to https://mcp.getle.ad/mcp as its audience, valid for one hour. Refresh tokens rotate: using one invalidates it.
Audience binding
A token minted for another resource is rejected, and the server never forwards a token onward. Access tokens carry a token-family id, so a revoke kills the live access token too rather than waiting for it to expire.

Discovery documents

Both documents are public and unauthenticated, which is what lets a client bootstrap itself.

discovery
curl -s https://mcp.getle.ad/.well-known/oauth-protected-resource
curl -s https://mcp.getle.ad/.well-known/oauth-authorization-server
PathSpecContains
/.well-known/oauth-protected-resourceRFC 9728The resource URI, its authorization servers and supported scopes.
/.well-known/oauth-authorization-serverRFC 8414Authorize, token, register and revoke endpoints, plus code_challenge_methods_supported: ["S256"].

401 and 403 responses

A missing or invalid credential returns 401 with a WWW-Authenticate header pointing at the protected resource metadata, so a compliant client can discover where to sign in:

401
WWW-Authenticate: Bearer error="invalid_token",
  error_description="Access token expired",
  resource_metadata="https://mcp.getle.ad/.well-known/oauth-protected-resource",
  scope="getlead:read"

A valid credential without the needed scope returns 403 with error="insufficient_scope" and the scope required for that tool, which is the signal to run a step-up authorization.

Revocation

  • API key: revoke it in Settings, MCP. The next call fails with 401.
  • OAuth connection: disconnect the client in Settings, MCP, or call /mcp/oauth/revoke with the refresh token. Both kill the whole token family.
  • Audit: the call history stays after revocation, so you can see what the credential did while it was live.
Something unclear? Ask in the app, or read the product overview.