Skip to main content
Most people never need this page. If you are connecting Claude, Claude Code, Cursor or VS Code, the client does all of this for you — go to Connect a client and click through the browser prompt. This page is for the other case: you are writing an MCP client, reviewing Attensira before listing or approving it, or debugging a flow that stops somewhere in the middle and you need to know exactly which document said what.

The three hosts

They are separate names on purpose. The resource server never sees a signing key, and the issuer string is one origin with no ambiguity about what it means.

Discovery

Start with an unauthenticated request to the MCP endpoint. It answers 401 with a challenge that points at the metadata:
Shell
Response header
Two paths serve the protected-resource document (RFC 9728), with identical bodies — clients differ on which one they probe:
Protected-resource metadata
Body
The authorization server publishes its own document (RFC 8414), again on two paths with the same body — the OpenID path exists only because several clients probe it first and fail closed on a 404. Attensira is not an OpenID Provider and never issues an id_token:
Authorization-server metadata

Endpoints

Every one of these is on auth.attensira.com only. The same paths on webapp.attensira.com return 404 — one issuer, one origin.

Scopes

There are exactly two, and there will not be a third in this version. attensira:write implies attensira:read; you do not need to request both, though clients commonly do. An authorize request that names no scope at all gets attensira:read only. A client that needs to change your workspace has to ask for it, so the consent screen can tell you that is what it is asking for. See the tool reference for which scope each tool needs.

Authorization code with PKCE

Only the authorization code grant is supported, and only with PKCE using S256. There is no implicit grant, no password grant, and code_challenge_method=plain is rejected.
Authorize request
The user signs in with Clerk, picks a workspace, and approves. The redirect back carries the code, your state echoed byte for byte, and the issuer:
Redirect
Then exchange it:
Shell
The authorization code is single use. A second exchange of the same code does not merely fail — it revokes the grant it came from, on the assumption that a replayed code means the code was stolen. You then have to reconnect. Make sure your client is not retrying the exchange on a network error without checking whether the first attempt succeeded.
redirect_uri is matched exactly against what the client registered. The single exception is RFC 8252 loopback — localhost, 127.0.0.1 and ::1 compare scheme, host and path and ignore the port, so a CLI that listens on an ephemeral port works. No other host gets that carve-out and there are no wildcards. The resource parameter (RFC 8707) must be exactly https://mcp.attensira.com/mcp. Anything else is invalid_target.

Client identification

Three ways to be a client, in the order Attensira prefers them:
  • Verified clients. Claude, Claude Code, mcp-remote, Cursor and VS Code are known to the authorization server, so the consent screen shows a real product name rather than a string the client supplied about itself.
  • Client ID Metadata Documents. Host a metadata document at an HTTPS URL and use that URL as your client_id. Nothing to register, nothing to expire.
  • Dynamic client registration. POST https://auth.attensira.com/oauth/register per RFC 7591, for clients that cannot do CIMD. Registration is rate limited by IP, redirect_uris is required and must be https:// or loopback, and a registration expires after 90 days of the client not being used.
No client secrets are issued, to anyone. The token endpoint’s only supported authentication method is none; a request that presents a secret is rejected with invalid_client. Every MCP client is a public client, and a secret shipped inside one is not a secret.
Anyone can register a client and choose its display name. The consent screen marks a self-registered client as unverified, and that badge is the only thing distinguishing a real integration from someone who registered “Attensira Official” an hour ago. Read the name, the badge and the requested scopes before you approve, and treat an unverified client asking for attensira:write as a thing to be sure about.

Tokens

Refresh tokens rotate: every use returns a new one and consumes the old. Replaying a consumed refresh token revokes the whole chain it belongs to, so a client that keeps a stale copy around and retries with it will log itself out. A well-behaved client stores only the newest. The access token names you by reference — the user, the workspace and the granted scopes — and carries no email, no name and no other personal data.
Sixty minutes is also the worst case after you revoke a connection. Revocation stops the next refresh immediately, but an access token already in a client’s hands stays valid until it expires. Plan on up to an hour, not instantly, and rotate anything else that was exposed alongside it.

Revoking

Two places, for two different situations. Revoke a whole connection from Settings → Connections in the app — this is what you want when a laptop is lost, a teammate leaves, or you no longer recognise something in the list. See Connected applications. A client can also revoke its own tokens at the endpoint, which is what a well-behaved client does when you sign out of it:
Shell
Per RFC 7009 this always answers 200, including for a token that was already revoked or never existed. A revocation endpoint that distinguished them would be a way to test whether a stolen token is live.

Errors

Errors use the RFC 6749 envelope, never a 200 with an error inside it:
Error body
The 401 from the MCP endpoint is deliberately the same string for every cause — missing, malformed, expired, wrong audience, bad signature. Telling a caller which one is true tells an attacker how close they are. Insufficient scope is a 403 and not a 401 on purpose: the token is fine, so a client that discards it and restarts discovery is doing the wrong thing. Reconnect with the wider scope instead.

Static keys still work here

None of this replaces atn_live_ keys. The MCP endpoint accepts an OAuth token or a static key, permanently, and headless callers such as n8n and CI should keep using keys — see API keys. The REST API does not use OAuth at all.