Authentication
Flux API delivers published content. Each Flux API instance can be public or require API keys. When authentication is enabled, every request must present a valid Flux API key using one of the supported methods. One exception has no toggle: write requests (POST/PUT and the MCP write tools) always require an authenticated key with the matching create/update grants — public APIs accept anonymous reads only.
Overview
- Configuration – Toggle authentication per API when creating or updating it through the Management API.
- Keys – Generate Flux API keys through the dashboard or Management API. Each key contains a Base64 public key and a private key that is shown only once.
- Methods – Flux API supports Secure (signature-based, for server-side and SDK integrations that can sign each request), Simple (static key pair, for clients where you write the
Authorizationheader yourself), and Bearer (an opaque token bound to a key, for hosted connectors that can only send theBearerscheme).
When an API is marked as “authentication required”, unauthenticated requests return 401 with error_code authentication_required.
API Key Components
When you create a Flux API key you receive:
- Name
public_key- Type
- string
- Description
Base64 encoded compressed P-256 public key. Appears in the
Authorizationheader.
- Name
secret_key- Type
- string
- Description
Base64 encoded private key in DER format. Used to sign data for Secure auth. The service never stores the full secret, so keep it safe.
- Name
bearer_token- Type
- string
- Description
Optional, and issued separately — see Bearer Token Authentication. Never returned by a key read; only its first 12 characters are, as
bearer_token_prefix.
Simple and Secure expect Base64 values exactly as they were issued. Do not decode or re-encode using different alphabets. A bearer token is opaque — send it byte for byte, and do not parse it.
Authentication Methods
- Name
Secure- Description
Signs each request using ECDSA P-256 + SHA256. Provides integrity, timestamp validation, and replay protection. Recommended for server-side and SDK integrations where code can compute a signature per request.
- Name
Simple- Description
Sends a static
{public}:{private}key pair. The right choice for any client where you control theAuthorizationheader — Claude Code, Cursor, custom clients, our SDKs. Pair it with a dedicated, narrowly scoped Flux key.
- Name
Bearer- Description
Sends an opaque
fxk_token bound to a Flux API key. For hosted connectors that cannot choose a scheme — they take a token field and always sendAuthorization: Bearer <token>. The token identifies the key; the key's role and grants are unchanged.
Pick by what the client lets you send, not by how sensitive the data is. All three resolve to the same key and the same permissions. If you can write the header yourself, use Simple (or Secure, if you can sign). If the client only offers a "token" field, you need a Bearer token.
Secure Authentication
Secure authentication verifies a signature built from the request path, body hash, and timestamp.
Because each signature covers the specific request body and timestamp, Secure signatures are per-request and cannot be pre-computed into a static header (for example, an MCP client config that only replays fixed headers). For those clients, use Simple authentication instead.
Required Headers
- Name
Authorization- Type
- string
- Required
- required
- Description
Secure <public_key>:<signature>where<signature>is Base64-encoded ECDSA output.
- Name
Date- Type
- string
- Required
- required
- Description
ISO 8601 UTC timestamp, e.g.,
2025-01-12T08:15:30Z. Requests older than 15 minutes are rejected.
Data to Sign
- Compute the SHA-256 hash of the request body. Use the empty string when no body is present (
e3b0c442…b855in hex). - Concatenate the pieces:
data_to_sign = "<request_path>|<body_hash>|<timestamp>"
request_path– The exact path sent to Flux API, including the API prefix and resource path (e.g.,/blog-api/articles/_search). Do not include the protocol or host.body_hash– Lowercase hex digest of the SHA-256 hash.timestamp– Same value as theDateheader.
- Sign
data_to_signwith your private key using ECDSA over the P-256 curve and SHA-256. Encode the signature in Base64 and include it in theAuthorizationheader.
import crypto from 'crypto';
import fetch from 'node-fetch';
const publicKey = process.env.FLUX_PUBLIC_KEY;
const privateKey = process.env.FLUX_PRIVATE_KEY; // Base64 DER
const uri = '/blog-api/articles/_search';
const body = JSON.stringify({
where: {
$: { all_of: [{ status__eq: 'published' }] }
}
});
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');
const timestamp = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
const dataToSign = `${uri}|${bodyHash}|${timestamp}`;
const sign = crypto.createSign('SHA256');
sign.update(dataToSign);
const signature = sign.sign({
key: Buffer.from(privateKey, 'base64'),
format: 'der',
type: 'pkcs8'
}).toString('base64');
const headers = {
Authorization: `Secure ${publicKey}:${signature}`,
Date: timestamp,
'Content-Type': 'application/json'
};
const response = await fetch(`https://7c9h4pwu.fxns.io${uri}`, {
method: 'POST',
headers,
body
});
console.log(await response.json());
Simple Authentication
Simple authentication sends a static public/private key pair in a single header, exactly like a bearer token:
Authorization: Simple <public_key>:<private_key>
The header never changes between requests, so it works in any client that can send a static Authorization header.
When to use it
Use Simple authentication wherever you write the Authorization header yourself — Claude Code, Claude Desktop, Cursor, agent frameworks, and custom clients. These replay a fixed header on every call and cannot compute a per-request signature, so Secure authentication is not an option there.
It is not an option for a hosted connector that only accepts a token value and sends it as Authorization: Bearer <token> — the scheme is fixed by the connector, so a Simple ... header can never be produced. Use a Bearer token there.
Server-side code and SDK integrations that can sign each request should prefer Secure authentication, which adds integrity, timestamp validation, and replay protection.
Security note
Simple authentication does not sign requests: the same static credential is presented on every call. Mitigate this the way you would any long-lived API token:
- Scope the key. Issue a dedicated Flux API key limited to only the APIs and collections the agent needs.
- Always use TLS. Send the header only over HTTPS so the credential is never exposed in transit.
- Rotate and revoke. Revoke a key immediately if it leaks, and rotate keys periodically.
- Cap spend. Set a spend cap on the key so a compromised credential cannot run up unbounded usage.
Bearer Token Authentication
A bearer token is an opaque credential bound to an existing Flux API key:
Authorization: Bearer fxk_A7fQ2mXe...
It exists for clients that give you a single token field and always send it with the Bearer scheme — most notably the Claude API MCP connector (mcp_servers[].authorization_token). Those clients cannot send Simple or Secure at all, which previously left every authentication-required Flux API unreachable from them.
What it changes, and what it does not
- Name
Identifies a key- Description
The token resolves to the Flux API key it was issued for. Role, grants, and per-collection
allowed_methodsare exactly the key's own — a token confers nothing extra and restricts nothing.
- Name
Independent of the key pair- Description
Issuing, re-issuing or revoking a token leaves
public_key,secret_keyandroleuntouched. Simple and Secure keep working throughout.
- Name
One per key- Description
Re-issuing replaces the previous token. There is no list of tokens to manage.
- Name
Shown once- Description
Only a hash is stored. The plaintext appears once, in the issue response — the same contract
secret_keyalready has. A lost token is re-issued, not recovered.
Issue, rotate and revoke
Tokens are managed through the Management API — see Flux API Keys → Bearer token.
# Issue (or replace) the token for a key
curl -X POST https://api.foxnose.net/v1/7c9h4pwu/permissions/flux-api/api-keys/dw2qC5qRwxuZ/bearer-token/ \
-H "Authorization: Bearer $MANAGEMENT_ACCESS_TOKEN"
# Revoke it. The key and its role keep working.
curl -X DELETE https://api.foxnose.net/v1/7c9h4pwu/permissions/flux-api/api-keys/dw2qC5qRwxuZ/bearer-token/ \
-H "Authorization: Bearer $MANAGEMENT_ACCESS_TOKEN"
Two different Bearer credentials exist and are not interchangeable. The Management API takes a JWT access token; the Flux API takes an fxk_ bearer token. A Flux token will not authenticate against api.foxnose.net, and a JWT will not authenticate against your Flux host.
Re-issuing is how you cut off a connector without disturbing anything else. The previous token stops working, while every integration using the key's public/private pair carries on. That is the whole reason the token is a separate credential rather than a field on the key.
Security note
The same considerations as Simple apply — the token is a long-lived static credential. In addition:
- Issue one only when a client needs it. A key has no token until you ask for one.
- Re-issue on suspicion. It is cheap and touches nothing else.
- Recognise it in logs and config. The
fxk_prefix makes a leaked token identifiable at a glance; the dashboard and API show only the first 12 characters (bearer_token_prefix).
Error Responses
When authentication fails, the Flux API returns 401 with JSON content similar to:
{
"message": "Invalid signature",
"error_code": "authentication_required",
"detail": null
}
Common reasons:
- Missing
AuthorizationorDateheader. - Incorrect path or body hash used during signature generation.
- Timestamp outside the ±15 minute window.
- Keys revoked or not authorized for the requested API prefix.
- A
Bearercredential that is not anfxk_token (for example a JWT meant for the Management API).
Verify all inputs before retrying to avoid throttling.
WWW-Authenticate
Every 401 carries a challenge listing the schemes a client can send a header for:
WWW-Authenticate: Simple realm="flux-api", Secure realm="flux-api"
Bearer is accepted but is deliberately absent from that list. The MCP specification tells a client that receives a Bearer challenge to begin OAuth discovery at /.well-known/oauth-protected-resource. Flux does not serve that document yet, so advertising Bearer would replace a clear 401 with a failed discovery round-trip. Bearer tokens work regardless of what the challenge says; this page is what tells you so.
The header will list Bearer — with a resource_metadata parameter — once OAuth support ships.