# Authentication — Threadlinqs Intelligence

Author: Threadlinqs Team · Canonical: https://intel.threadlinqs.com/auth.md · Last reviewed: 2026-10-29

How a program (agent, script, MCP host, TAXII client) authenticates to Threadlinqs Intelligence. Two hosts: https://intel.threadlinqs.com (the REST API, the MCP endpoint, the entity pages) and https://threadlinqs.com (sign-in, pricing, marketing). Every credential is issued on intel and works on intel.

## No credential needed
- Entity pages and their Markdown twins (append `.md`), /llms.txt, /llms-full.txt, /feed.xml, /feed.json, /sitemap-index.xml, /mcp.md, /mcp/catalog.json, /mcp/skill.md.
- Discovery documents: https://intel.threadlinqs.com/.well-known/api-catalog (RFC 9727), https://intel.threadlinqs.com/.well-known/mcp/server-card.json, https://intel.threadlinqs.com/mcp/server-card, https://intel.threadlinqs.com/.well-known/ai-catalog.json, https://intel.threadlinqs.com/.well-known/agent-skills/index.json, https://intel.threadlinqs.com/.well-known/mcp.json.
- Tier-0 REST routes answer anonymously with the public projection (for example `GET /api/v1/stats`, `GET /api/v1/threats?lean=1`); gated fields come back as locked stubs with an `unlock` hint rather than values.

## Scheme 1 — API key (`Authorization: Bearer tl_…`)
- Send `Authorization: Bearer tl_<key>` on any `/api/v1/*` route or on `POST /mcp`. The key carries the account's tier (see Tiers). The key spends the account's TL Creds (see TL Creds).
- Where a human mints it: sign in at https://threadlinqs.com, open the profile and generate an API key (the browser calls `POST /api/v1/user/api-key` with the session; `GET` reports whether one exists). The key is shown once. Generating again replaces the previous key; the profile can also revoke it.
- Enforced: 5 key generations per account per hour, then `429` with `Retry-After: 3600`.

## Scheme 2 — OAuth 2.1 for the MCP endpoint
- Protected resource: https://intel.threadlinqs.com/mcp. RFC 9728 metadata: https://intel.threadlinqs.com/.well-known/oauth-protected-resource (also at /.well-known/oauth-protected-resource/mcp). RFC 8414 metadata: https://intel.threadlinqs.com/.well-known/oauth-authorization-server (also with the /mcp suffix).
- Issuer https://intel.threadlinqs.com; authorization endpoint https://intel.threadlinqs.com/oauth/authorize; token endpoint https://intel.threadlinqs.com/oauth/token; grants `authorization_code` and `refresh_token`; PKCE `S256` required; `token_endpoint_auth_methods_supported: ["none"]` (public clients); scope `mcp`.
- Client ID Metadata Documents (CIMD): `client_id` is the HTTPS URL of your client's metadata document; no pre-registration.
- Access tokens live 1 hour; refresh tokens 30 days.
- `initialize` and `ping` need no credential (they always answer `200`; OAuth hosts bootstrap from them). The first gated method (`tools/list`, `tools/call`, `prompts/*`, `resources/*` other than `ui://`) sent WITHOUT an `Authorization` header answers `401` with `WWW-Authenticate: Bearer realm="threadlinqs-mcp", resource_metadata="https://intel.threadlinqs.com/.well-known/oauth-protected-resource", scope="mcp"` and a JSON-RPC error -32001 in the body. With a header that does not resolve to an account, the answer is HTTP `200` carrying JSON-RPC error -32001 (no challenge); a resolved account below Purple gets -32002.
- Authorization is granted to Purple or Gold accounts (tier >= 3); a lower tier is refused at the consent step. MCP tool calls on both transports require tier >= 3.
- Enforced: 40 requests per minute per IP across /oauth/authorize and /oauth/token, then `429` with `Retry-After: 60`.

## Scheme 3 — HTTP Basic (TAXII 2.1 and other standards clients)
- `Authorization: Basic base64(<any-username>:tl_<key>)`. The username is ignored; the password must be the API key. The server normalises it onto the Bearer path: same key, same tier, same limits.
- TAXII 2.1 discovery: https://intel.threadlinqs.com/api/v1/taxii2/ (Gold). MISP feed manifest: https://intel.threadlinqs.com/api/v1/feeds/misp/manifest.json (Purple or Gold). STIX 2.1 export: https://intel.threadlinqs.com/api/v1/export/stix (Purple or Gold).

## Tiers
| Tier | Name | Unlocks |
|---|---|---|
| 0 | Anonymous / unverified | Public projection only |
| 1 | Blue | The threat feed, MITRE ATT&CK coverage, daily debriefs, one complete detection per threat (Splunk SPL, Microsoft KQL, Sigma) and the Research Lab, priced per prompt. 10 daily creds; unlocking the rest of a threat's rules costs 5 creds. |
| 2 | Red | Everything in Blue, plus the correlation engine, actor attribution and DNS lookups. 25 daily creds; unlocking a threat costs 5 creds and includes indicator values. |
| 3 | Purple | Everything in Red, plus the MCP server, attack simulations, advanced correlations, Wild C2 intelligence, STIX 2.1 export and the MISP feed. 150 daily creds; unlocking a threat costs 5 creds and opens its full intelligence. |
| 4 | Gold | Everything in Purple, plus SecOS for Teams, tenant audit and offboarding, shared case files and SLA-backed support. Gold team plans are metered, not limited. Each action that costs creds on a personal plan is recorded for your team at its usual price (5 creds to unlock a threat on the website, 3 with an API key or MCP, 10 for an export). Nothing is charged to anyone, nobody on the team is refused for lack of creds, and team plans do not use top-ups. |

Blue is a free account with a verified email. Pricing: https://threadlinqs.com/pricing (Markdown: https://intel.threadlinqs.com/pricing.md). The MCP server is tier >= 3 on both transports.

## TL Creds
Report content is unlocked with TL Creds ("creds"). One complete detection per threat (Splunk SPL, Microsoft KQL, Sigma) is free for everyone; the other rules, indicator values, similar threats, attack flow, exports and some analysis tools unlock with creds. Prices, packs and earning rules: https://threadlinqs.com/tl-creds
- Every account includes daily creds: 10 on Blue, 25 on Red and 150 on Purple. They reset at midnight Toronto time and do not carry over. Gold team plans are metered, not limited.
- Unlocking a threat costs 5 creds at your plan's starting level: its detection rules on Blue, its detection rules and IOC values on Red, its full intelligence on Purple. A threat you unlock stays unlocked.
- API keys and MCP spend creds automatically, 3 creds per threat, from daily and earned creds, up to 30 creds a day on Blue, 75 on Red and 450 on Purple. Purchased creds are used only after you turn on API and MCP spending in your profile. When the account has too few creds for a request, a threat read returns the locked version of the threat, and a single detection, export or tool call answers HTTP 402 with the code credits_required. A request that would take the daily spending past the cap is refused with HTTP 429 and the code api_cap_reached plus a reset_at time: wait until reset_at and do not retry before it.
- A call that charges for a tool (a day pass or a per-call tool) carries X-TL-Charged (what that call cost) and X-TL-Creds (daily remaining, earned, purchased). A threat read, a similar-threats read or an export that unlocks automatically carries neither: GET /api/v1/creds returns the balance. A full-mode GET /api/v1/threats list carries X-TL-Locked: how many threats on the page are still locked.
- Gold team plans are metered, not limited. Each action that costs creds on a personal plan is recorded for your team at its usual price (5 creds to unlock a threat on the website, 3 with an API key or MCP, 10 for an export). Nothing is charged to anyone, nobody on the team is refused for lack of creds, and team plans do not use top-ups. Gold responses carry no X-TL-Creds, X-TL-Charged or X-TL-Auto header and are never answered 402 or 429 for creds; X-TL-Locked still appears on full-mode threat lists and saved views.
- Agent keys (tla_) hold no creds and spend none: reads return the public projection, and locked content comes back as a stub.
- MISP and TAXII feeds are not metered with creds.
- The opt-in for purchased creds is a profile switch (POST /api/v1/creds/api-purchased, browser session only, off by default).

## Enforced limits
- `POST /mcp`: 120 requests per minute per credential (per IP when anonymous); over it, `429` with a JSON-RPC error (code -32000).
- `/oauth/authorize` and `/oauth/token`: 40 requests per minute per IP; `429`, `Retry-After: 60`.
- `POST /api/v1/user/api-key`: 5 per account per hour; `429`, `Retry-After: 3600`.
- DNS enrichment lookups (`GET /api/v1/iocs/<value>/dns` and the live/profile variants): 100 per day on Red, 1000 on Purple, unlimited on Gold, reset at midnight America/Toronto; over it `429` with a JSON body `{"error":"Daily DNS lookup limit reached","used":n,"limit":n}`.
- API and MCP spending: up to 30 creds a day on Blue, 75 on Red and 450 on Purple (3 times the daily allowance), reset at midnight America/Toronto; over it, `429` with `{"code":"api_cap_reached","reset_at":"…"}`. Gold team plans have no cap.
- No daily quota is enforced on other REST routes or on MCP tool calls at the time of writing for human (`tl_`) keys; agent (`tla_`) keys carry the enforced daily quota under Agent registration. The edge may answer `429` with a `Retry-After` of its own; honour it. Spending is capped as above.

## Errors
- `401` — missing or invalid credential on a REST route (`{"error":"Unauthorized"}`). On /mcp only a gated method with NO `Authorization` header answers `401` (JSON-RPC -32001 plus the `WWW-Authenticate` challenge above); a present-but-invalid credential answers `200` with JSON-RPC -32001.
- `402` — `credits_required` on a single-resource read (see 402 credits_required below).
- `403` — valid credential, insufficient tier (on /mcp a JSON-RPC error -32002 with `required_tier`).
- `429` — a limit above (`api_cap_reached` for the API and MCP spending cap); read `Retry-After` or `reset_at`.

## Agent registration
Self-service, for programs without a human account: no Turnstile, no email, no sign-in. Register once, store the key, then authenticate with Scheme 1 (`Authorization: Bearer tla_<key>`).
- `POST https://intel.threadlinqs.com/api/v1/agents/register` with a JSON body `{"name": "<agent name>", "operator_contact": "<email or https URL>", "purpose": "<optional>", "agent_url": "<optional>"}` (`name` and `operator_contact` required). Answers `201` with `{"api_key": "tla_…", "tier": "blue", "quota_per_day": n, "docs": "https://intel.threadlinqs.com/auth.md", "catalog": "https://intel.threadlinqs.com/.well-known/api-catalog"}`. The key is shown once. A malformed body answers `400` with `{"error": …}` naming what is wrong.
- Registration is server-to-server: send `Content-Type: application/json` (else `415`) and a `Content-Length` (else `411`; over 8 KB `413`). A request carrying an `Origin` header or a `Sec-Fetch-Site` other than `none` (a browser page) answers `403` with `{"error":"browser_request"}` — a web page cannot mint keys from its visitor's address.
- Key prefix `tla_` (a human key is `tl_`). The account is Blue (tier 1): every tier-1 REST route and the public projection, nothing above it.
- Registration limits: 3 keys per IP per day and 1 per operator contact per day; over either, `429` with `Retry-After` (one generic `{"error":"rate_limited","reset_at":"…"}` whichever limit it is; an IPv6 address counts per /64; a global daily ceiling backs both).
- Enforced daily quota per agent key: 200 requests per day by default (the `quota_per_day` the registration answer reports), reset at midnight America/Toronto; over it, `429` with `{"error":"quota","reset_at":"…"}`. Every `/api/v1` request sent with the key counts, refused ones included (`403` on a route above the tier, `404`); `GET /api/v1/agents/me` and `POST /api/v1/agents/rotate` do not. The count is booked before the request is served, so parallel requests cannot pass the limit. This is the one REST quota the server enforces today — human keys are counted, not cut off.
- `GET https://intel.threadlinqs.com/api/v1/agents/me` (Bearer `tla_` key) → the account, today's usage and the quota.
- `POST https://intel.threadlinqs.com/api/v1/agents/rotate` (Bearer `tla_` key) → `201` with a new `api_key`; the old key stops authenticating at once. A suspended or revoked key stops authenticating too.
- What an agent key cannot do: buy anything, hold TL Creds, open the Lab, reach Purple or Gold routes (`403`) or call `/mcp` (tier >= 3). Those need a human account and a `tl_` key (Scheme 1). The credit-metered AI helpers (`POST /api/v1/tlql/translate`, `explain`, `suggest-name`, `diagnose-empty`, `POST /api/v1/search/ai/semantic`, `search/ai/rag`) answer `403` with `{"error":"agent_principal","family":"metered"}`; `GET /api/v1/billing/catalog` (public pricing) stays readable.
- A `tla_` key that is unknown, suspended or revoked answers `401` on every `/api/v1` route — it is never downgraded to an anonymous request. `GET /api/v1/user/usage` with an agent key reports the agent meter (`api_calls_today`, `limits.api_daily` = the quota, plus an `agent` object).
- On a deployment whose agent tables are not provisioned yet, the three routes answer `503` with `{"error":"agent_signup_unavailable"}` and a `tla_` key does not authenticate (`401`).

## 402 credits_required
When the account has too few creds for a request:
- A threat read (`GET /api/v1/threats/{id}`, MCP `get_threat`) answers `200` with the locked version of the threat and `unlock.credits_required: true`.
- A single detection, export, tool call, OSINT read or infrastructure-pivot read answers `402` with `{"code":"credits_required",…}` and the price in `cost` (`export_cost` on an export); when only purchased creds could pay, the body also carries `purchased_available`, `opt_in {setting, url}` and a `hint`. Over MCP the same body arrives inside the tool result, marked as an error.
- Do not retry in a loop. Daily creds reset at midnight America/Toronto; a person can top up, or turn on API and MCP spending, in their profile. Gold team plans never receive this answer.
- Planned, not live: a separate payment scheme (x402 / Cloudflare Monetization Gateway) would answer `402` with `{"error":"payment_required", …}` plus that scheme's payment-challenge headers. It is a different code from `credits_required`, and the `401` / `403` semantics above stay unchanged.

## Related
- API catalog: https://intel.threadlinqs.com/.well-known/api-catalog · MCP server card: https://intel.threadlinqs.com/.well-known/mcp/server-card.json and https://intel.threadlinqs.com/mcp/server-card · AI catalog: https://intel.threadlinqs.com/.well-known/ai-catalog.json · Agent skills: https://intel.threadlinqs.com/.well-known/agent-skills/index.json
- MCP docs: https://intel.threadlinqs.com/mcp (Markdown: https://intel.threadlinqs.com/mcp.md) · llms.txt: https://intel.threadlinqs.com/llms.txt · Terms: https://threadlinqs.com/terms
- TL Creds: https://threadlinqs.com/tl-creds · TL Creds (Markdown): https://intel.threadlinqs.com/tl-creds.md
