---
title: auth.md — Fractional Teams Portal
description: How an AI agent obtains, uses, and revokes credentials for the Fractional Teams Portal API and MCP server.
canonical: https://portal.fractionalteams.com/auth.md
last-updated: 2026-09-08
---

# Authentication walkthrough (auth.md)

This document follows the auth.md convention (a prose walkthrough an agent can follow step by step). The portal uses **per-user bearer API keys**, not OAuth: there is no authorization server, no `agent_auth` endpoint and no dynamic `register_uri` — a human issues the key.

## 1. Discover

- Protected resource metadata (RFC 9728): `https://portal.fractionalteams.com/.well-known/oauth-protected-resource` — lists the resource, the accepted bearer method (`header`), the supported scopes and this document.
- An unauthenticated call to the API or MCP returns `401` with `WWW-Authenticate: Bearer resource_metadata="https://portal.fractionalteams.com/.well-known/oauth-protected-resource"`.
- Human-readable docs: `https://portal.fractionalteams.com/docs`. Machine-readable API: `https://portal.fractionalteams.com/openapi.json`.

## 2. Pick a method

There is exactly one credential type:

| Method | Header | Who issues it | Scope |
| --- | --- | --- | --- |
| Portal API key | `Authorization: Bearer ftpk_...` | A portal user (or an account admin) on the web account page | Inherits that user's section scopes, lead-marking permission and own-leads-only restriction |
| No credential / `Bearer demo` | (none) | — | The public demo workspace only |

There is no OAuth 2.0 flow, no client-credentials grant, no identity_assertion / id-jag exchange and no API-side key minting. This is deliberate: a leaked key can read what its user can read but can never create or rotate credentials.

## 3. Register

Nothing to register. The human who owns the account must already be a Fractional Teams client user. If they are not, they contact help@fractionalteams.com (see https://portal.fractionalteams.com/contact).

## 4. Claim a credential

Ask the human to:

1. Sign in at https://portal.fractionalteams.com/login.
2. Open **Account & security** (https://portal.fractionalteams.com/account) → **API keys** → **Create key**.
3. Copy the key (`ftpk_` followed by 32 URL-safe characters). It is shown **once**; the portal stores only a hash.
4. Hand it to you through your host's secret mechanism — never paste it into a chat transcript that is logged.

A user may hold at most 3 active keys. An account admin can also create a key for a user under *Admin → client → Users*.

## 5. Use the credential

REST:

```
curl -H "Authorization: Bearer ftpk_your_key" https://portal.fractionalteams.com/api/v1/me
```

MCP (Streamable HTTP, stateless, POST only):

```
claude mcp add --transport http portal https://portal.fractionalteams.com/mcp --header "Authorization: Bearer ftpk_your_key"
```

`GET /api/v1/me` (or the `get_me` tool) tells you exactly what the key can see: `scopes` (`"*"` or a list of seo, aeo, geo, smm, outreach, paid_media, plan), `can_mark_leads`, and `outreach_owner`.

Scopes are properties of the **user**, set by a Fractional Teams admin; every key the user holds inherits them at request time. Scope names: `seo`, `aeo`, `geo`, `smm`, `outreach`, `paid_media`, `plan`, `leads:mark`.

## 6. Errors

| Status | Body | Meaning | What to do |
| --- | --- | --- | --- |
| 401 | `{"error":"unauthorized"}` | Missing, malformed, revoked or unknown `ftpk_` key (a malformed key never falls back to the demo) | Stop and tell the human; do not retry |
| 403 | `{"error":"..."}` | The key lacks a capability on its own data (outreach scope, lead-marking) | Explain which permission is missing; an admin must grant it |
| 404 | `{"error":"not found"}` | Outside this key's scope, another client's data, or a draft | Treat as non-existent |
| 429 | `{"error":"rate limit exceeded"}` | 120 req/min per key exceeded | Wait `Retry-After` seconds |

MCP returns the same conditions as JSON-RPC errors (401 → code -32001) or tool results with `isError: true`.

## 7. Revocation

- The human revokes, reissues or deletes the key on https://portal.fractionalteams.com/account (an admin can do the same). Revocation takes effect on the next request — nothing is cached.
- Reissue rotates the secret in place: the old value dies instantly, the key's settings survive.
- Disabling the user, or the admin changing the user's scopes, applies to every key the user holds immediately.
