Operating system set to macOS
Documentation jurisdiction set to United States
Sign inConnect Claude

Authentication

Get Past the Front Door

Auth trips up more first calls than anything else, so it leads here. MCP clients use OAuth 2.1 with dynamic client registration and PKCE. Backends and scripts use an API key. The browser uses your portal session. Pick the path for the surface you call from.

Three Paths, One Authenticated Request

Every call resolves to the same authorized identity. The difference is how you present it.

Calling fromUseHow it travels
Claude Code / Desktop / Cursor / any MCP clientOAuth 2.1 bearerAuthorization: Bearer … (the client handles it)
cURL / SDK / CLI / partner backendAPI key (sk_*)Authorization: Bearer sk_…
Browser inside the portal (playground)Portal session cookieCookie, set on sign-in. No header.

The most common path

OAuth 2.1 for MCP Clients

When a client first reaches the Archie MCP server, it has no token. The server answers 401 with a WWW-Authenticate header that points at the protected-resource metadata. The client reads that, discovers the authorization server, registers itself, runs a PKCE authorization, and exchanges the code for a token. Every step is standard OAuth 2.1, so a conformant client does it without you writing any auth code.

MCP client
Archie
  1. 1
    POST /mcp

    First call, no token yet.

  2. 2
    401 + WWW-Authenticate

    Points at the protected-resource metadata (RFC 9728).

  3. 3
    GET /.well-known/oauth-protected-resource

    Client reads the resource metadata.

  4. 4
    GET /.well-known/oauth-authorization-server

    Discovers the auth server (RFC 8414).

  5. 5
    POST /oauth/register

    Dynamic client registration (RFC 7591). No pre-shared client id.

  6. 6
    client_id

    The client is now registered.

  7. 7
    GET /oauth/authorize (PKCE S256)

    User picks Google or Microsoft and approves the scopes.

  8. 8
    302 → redirect_uri + code

    Authorization code returned to the client.

  9. 9
    POST /oauth/token (code + verifier)

    Exchanges the code for an access token.

  10. 10
    access_token

    Bearer token, scoped to the approved permissions.

  11. 11
    POST /mcp (Authorization: Bearer …)

    The original call, now authenticated. Archie runs it.

Discovery and registration endpoints

StepEndpoint
Protected-resource metadata (RFC 9728)GET https://mcp.dev.arch.ie/.well-known/oauth-protected-resource
Authorization-server metadata (RFC 8414)GET https://api.dev.arch.ie/.well-known/oauth-authorization-server
Dynamic client registration (RFC 7591)POST https://api.dev.arch.ie/oauth/register
Authorization (PKCE S256)GET https://api.dev.arch.ie/oauth/authorize
Token exchangePOST https://api.dev.arch.ie/oauth/token

The canonical resource indicator is https://mcp.dev.arch.ie/mcp. The /mcp suffix matters, because the OAuth resource indicator is canonicalized against it. Use the full path everywhere you configure the server.

Why no client secret

Dynamic Client Registration

You never paste a client id or secret into your MCP client. Archie supports dynamic client registration (RFC 7591): on first connect the client registers itself with the authorization server and receives its own client_id on the spot. This is what makes a one-URL connector possible. There is no developer-portal step to create an OAuth app before you can connect.

  • Public clients (desktop apps, editors) register without a secret and prove possession with PKCE, so there is no long-lived secret to leak.
  • Registration is bound to the redirect URIs the client declares. Archie allowlists the Claude callback URIs and loopback for local clients; an unrecognized redirect URI is refused.
  • Each connection gets its own registration, so revoking one client does not affect another.
Directory note
For the Anthropic Connector Directory, both Claude callback URIs (https://claude.ai/api/mcp/auth_callback and https://claude.com/api/mcp/auth_callback) plus loopback are allowlisted on the authorization server. DCR is enabled. No per-developer OAuth-app creation is required.

What the user approves

Consent and Scopes

On the authorization step the user signs in with WorkOS (Google or Microsoft) and approves a set of scopes. The token Archie issues carries exactly those scopes, and every call is gated against them server-side. A user who cannot see a client in the web app cannot reach that client through a token either.

The scope vocabulary is the eleven-permission taxonomy the skill registry enforces: every skill declares exactly one required permission, and the bearer must carry it for the dispatch to pass. API keys pick from the same catalog, so a scope you see here is also a permission you can put on a key.

ScopeGrantsExample skills
accounting:writeBookkeeping writes — post journal entries, enrich trial-balance rows, flag duplicates.record_journal_entry, enrich_tb_rows, detect_tb_duplicates
ask:executeAsk Archie a question — the conversational entry point plus the open-ended advisory and research skills built on it.ask_archie, advise_tax, research_standards
clients:readRead client financial and payroll data and run analyses over it.list_clients, get_client_financials, analyse_financials
documents:analyseAnalyse uploaded documents and review them against compliance requirements.analyse_document, review_compliance, audit_workpaper_review
email:draftDraft client communications for human approval.prepare_communication
reports:generateGenerate reports, memos, and packs — financial reports, CFO packs, accounting memos.prepare_financial_report, prepare_cfo_pack, prepare_asc606_memo
search:readKnowledge-base search.search_knowledge
topics:readList and read topics and their message history.topic_list, topic_get, topic_messages
topics:writeCreate topics and link conversations into them.topic_create, topic_link_conversation
workstreams:readList WorkStreams and inspect cycle status.workstream_list, workstream_describe, workstream_status
workstreams:writeRun, advance, approve, and cancel WorkStreams.workstream_run, approve_or_reject, workstream_cancel
Retired scopes (2026-06 consolidation)
The earlier vocabulary — messages:create, conversations:read, documents:read, drafts:write, journal:write, reports:read, standards:read, workstreams:execute — is retired. Retirement is enforced at mint time: /oauth/authorize rejects a retired scope with invalid_scope, and creating an API key with one fails with 400 unknown_permissions (the response lists the valid slugs). Existing keys needed no action: the 2026-06-10 consolidation rewrote the old registry slugs in place on every key (e.g. client:read → clients:read, workstream:execute → workstreams:write), and the retired strings above were never required by any skill, so keys still carrying them lose nothing — they keep authenticating and the inert strings simply match nothing. If you want such a key to hold meaningful scopes, create a replacement with the table above and revoke the old one — rotation copies the parent's permission list verbatim, so rotating alone does not change scopes. Rough intent translation: messages:create → ask:execute; conversations:read → topics:read; documents:read → documents:analyse; drafts:write → email:draft; journal:write → accounting:write; reports:read → reports:generate; standards:read → ask:execute; workstreams:execute → workstreams:write.

A token minted with no scope parameter carries the legacy archie:full wildcard and keeps full access, so pre-narrowing OAuth connections behave as before. Scopes are enforced by WorkOS FGA on top of the workspace-membership gate. Read-only tools never write; write tools that cross a risk threshold defer to the confirmation contract.

How long it lasts

Token Lifetime and Refresh

  • An access token lives as long as the WorkOS session that backs it (default eight hours). The client refreshes transparently; you do not handle the refresh yourself.
  • Revoke a connection from Dashboard → Connections. The next call from that client returns 401.
  • A token that does not begin with sk_ short-circuits the API-key validation path, so JWT bearers stay on the fast path.

For backends and scripts

API Keys

Mint a key in Dashboard → Keys → Create key. Pick the permissions you need. The full sk_* value shows once, so copy it then. After that the portal stores only the prefix; you cannot retrieve the full value again.

terminalbash
curl https://api.dev.arch.ie/api/v1/skills/workstream.list/invoke \
  -H "Authorization: Bearer $ARCHIE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"limit": 5}'

The backend validates the key against WorkOS and caches the result for five minutes per token, so the round-trip stays off the hot path. Revoking a key takes effect on the next call within that window; a rotated key keeps its parent alive for a grace period (default 24h) while you roll the new value into your secrets store.

Test keys are bounded
A test key is isolated from live data and carries its own per-key credit cap. A leaked test key cannot reach a live workspace and stops working when its credit is spent. See Managing keys for rotation, pinning, and per-key metadata.

In the browser

Portal Session

When you sign into the developers portal, WorkOS sets a session cookie. Any portal page (the playground included) calls the API with the cookie attached and the same authorization gate fires. No header needed. For programmatic or cross-origin calls, use an API key instead, since the cookie path is browser-only.

Resolution Order

Server-side, the router tries each path in order and stops at the first hit. Knowing the order helps when you are debugging why a call authenticated as a particular identity.

  • Already-authenticated request state, set by middleware from the session cookie or E2E bypass.
  • Bearer Archie session JWT (HS256, internal secret).
  • Bearer Archie OAuth JWT (RS256, validated against the WorkOS JWKS).
  • Bearer WorkOS API key (sk_*, validated via the WorkOS SDK).

When Auth Fails

Authentication failures return 401 with the canonical error envelope. Branch on code, never on message.

401 responsejson
{
  "error": {
    "type": "authentication_error",
    "code": "auth_required",
    "message": "Authorization: Bearer <token> required. Accepts an Archie session JWT, an Archie OAuth JWT, or a WorkOS-issued API key (sk_*)."
  }
}

Common codes: auth_required, invalid_token, insufficient_scope, workspace_not_found, rate_limited. The full dictionary lives in Error handling.