MCP Authentication
How the Threatmatic MCP toolbox authenticates requests using org API keys and enforces strict org-scoped data access.
All org-scoped MCP tools require an api_key parameter. This key identifies and authenticates your organization — no separate login step, no session tokens. The key is validated on every query, directly in the database.
How it works
Pass your org API key
Every tool call includes api_key as the first parameter:
# Git Bash
toolbox.exe invoke --config tools.yaml list-devices \
'{"api_key":"org_hYERT..."}'
# PowerShell
$params = '{"api_key":"org_hYERT..."}'
.\toolbox.exe invoke --config tools.yaml list-devices $paramsThe key is hashed and looked up
The validate_org_api_key Postgres function runs on every query:
CREATE OR REPLACE FUNCTION validate_org_api_key(input_key text)
RETURNS uuid AS $$
SELECT reference_id::uuid
FROM apikey
WHERE key = rtrim(translate(encode(sha256(input_key::bytea), 'base64'), E'+/\n=', '-_'), '=')
AND prefix = 'org_'
AND enabled = true
AND (expires_at IS NULL OR expires_at > now())
LIMIT 1;
$$ LANGUAGE sql STABLE;Step by step:
sha256(input_key::bytea)— hashes the raw key. Better Auth never stores plaintext API keys, only their SHA-256 hash.encode(..., 'base64')+translate(...)— converts the hash to base64url (replaces+→-,/→_, strips newlines and=padding) to match the 43-character format stored in theapikeytable.WHERE key = <hash> AND prefix = 'org_' AND enabled = true AND ...— finds the matching row and returnsreference_id(the organization UUID), orNULLif the key is invalid, disabled, or expired.
The org ID scopes every query
Every tool uses the returned UUID to filter data:
WHERE organization_id = validate_org_api_key($1)The org ID is derived from the key server-side. It is never supplied by the caller — there is no way to query another organization's data by passing a different ID.
Security properties
| Property | How it's enforced |
|---|---|
| Org isolation | organization_id comes from the key, not the caller |
| Invalid key → no data | validate_org_api_key returns NULL; col = NULL matches nothing in Postgres |
| Expired keys stop working | expires_at > now() checked on every call |
| Disabled keys stop working | enabled = true checked on every call |
| User keys rejected | prefix = 'org_' rejects usr_ keys |
| No write operations | All tool SQL is SELECT only — no INSERT, UPDATE, DELETE, or DDL |
Toolsets
| Toolset | Who uses it | Auth required |
|---|---|---|
netra-org | Customers, agents, integrations | Org API key (org_ prefix) |
netra-admin | Threatmatic internal | Connection-level (no key param) |
The netra-org toolset is the only one exposed to external callers. It contains all telemetry, device, policy, zone, and app catalog tools.
Getting your org API key
Org API keys are managed in the Threatmatic console under Settings → API Keys. Keys are prefixed with org_. Create a dedicated key for each integration or AI assistant — keys can be disabled individually without affecting others.
How is this guide?
Last updated on