Skip to content
NeuralRepo
Get Support

Authentication

All API endpoints (except /api/v1/health) require authentication. NeuralRepo accepts a session token, an API key, or a session cookie, and resolves them in a fixed order.

Every /api/v1/* request runs through the same middleware chain before your endpoint sees it:

yeshitmisshitmissnoyeshitmissnoyeshitmissnoRequest to /api/v1/*Authorization: Bearerpresent?Look up SHA-256 of thetokenin sessions, unexpired onlySession userscopes = null, expirypushed to +30 daysLook up the same hash inapi_keysAPI-key userscopes from the key row,last_used_at updatedX-API-Key starting withnrp_ ?Look up SHA-256 of thekey in api_keysCookie nrepo_sessionpresent?Look up SHA-256 insessionsrefresh expiry and re-setthe cookie401 UnauthorizedLoad plan from usersRate limitAPI-key and Bearerrequests onlyEndpoint handler

In prose, so nothing here lives only in the diagram:

  1. If an Authorization: Bearer header is present, its SHA-256 hash is looked up in the sessions table first, then in the api_keys table. That is why a bearer token can be either credential.
  2. Otherwise an X-API-Key header is tried, but only if it starts with nrp_ — a key sent under that header without the prefix is ignored entirely.
  3. Otherwise the nrepo_session cookie is tried.
  4. If none matches, the request is rejected with 401 and the body { "error": "Unauthorized" }. The message is the same whether the credential was missing, malformed, revoked, or expired.
  5. A match sets the user and their plan; a session match also slides its expiry 30 days forward.
  6. The rate limiter then runs, but only for API-key and bearer-token requests.

When you sign in through the NeuralRepo web app, a session token is stored in a secure HTTP-only cookie. You can also pass it explicitly:

Authorization: Bearer <session_token>

Sessions last 30 days and slide: every authenticated request pushes the expiry another 30 days out, so an active session effectively never expires while a dormant one lapses after a month. Signing out via /auth/logout deletes the row immediately.

API keys provide long-lived access for scripts, CI pipelines, and third-party integrations. Every key is the prefix nrp_ followed by 64 hexadecimal characters (32 random bytes):

X-API-Key: nrp_a1b2c3d4e5f6...

Keys do not expire. Only the SHA-256 hash is stored, so a lost key cannot be recovered — only revoked and replaced.

Terminal window
curl -X POST https://neuralrepo.com/api/v1/user/api-keys \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{"label": "CI Pipeline"}'

label is optional and defaults to default; it is capped at 100 characters.

Response 201 Created

{
"id": "3f2a91c47b0e4d5aa8c61e0f2b7d4c93",
"key": "nrp_a1b2c3d4e5f67890...",
"label": "CI Pipeline",
"created_at": "2026-03-24 12:00:00"
}

The id is a 32-character hex string — it is what you pass to the delete endpoint, and it is not the key.

GET /api/v1/user/api-keys

Returns every key on the account, newest first. The response carries no key material at all — not a masked value, not a prefix. Each entry is id, label, scopes, source, last_used_at, and created_at. source is manual for keys you created here and mcp for keys minted by the MCP OAuth flow.

DELETE /api/v1/user/api-keys/:id

Deletes the row, so the key stops working on the next request. Returns 200 OK with { "success": true }, or 404 if the id does not belong to you. Unlike key creation, revoking is available on every plan.

Scopes are stored per key and are null for every key you create yourself, which means full access. Only tokens minted by the MCP OAuth flow carry a scope string:

ScopeGranted toDescription
ideas:readMCP OAuth tokensRead ideas, tags, relations, links, search, map, duplicates
ideas:writeMCP OAuth tokensCreate, update, archive, merge, and develop ideas; manage tags, links, and relations

A token whose scope string omits the scope an endpoint requires gets 403 { "error": "Insufficient scope: requires ideas:write" }. Session tokens and manually created API keys never see that error, because they are unscoped.

NeuralRepo issues MCP (Model Context Protocol) tokens for AI assistant integrations. The flow is separate from standard API authentication and is driven by the client, not by you:

  1. You add https://neuralrepo.com/mcp/ as an MCP server in a compatible client.
  2. The client discovers the endpoints from /.well-known/oauth-authorization-server, registers itself, and walks the authorization-code + PKCE flow at /mcp/authorize and /mcp/token.
  3. The token it receives is written to the same api_keys table with source = "mcp", a label of MCP (<client>), and the scopes you approved.

GET /api/v1/user/mcp-tokens lists the tokens issued this way — it does not create one. Revoke them with the same DELETE /api/v1/user/api-keys/:id endpoint used for manual keys.

StatusBodyMeaning
401 Unauthorized{ "error": "Unauthorized" }Missing, malformed, revoked, or expired credential
403 Forbidden{ "error": "Insufficient scope: requires ideas:write" }Valid MCP token, wrong scope
403 Forbidden{ "error": "API access requires a Pro plan", "pro_required": true, ... }Valid credential, plan gate

There is no distinct “invalid API key” message — every authentication failure returns the same 401 body, by design.

  • Use API keys for server-side scripts and automations.
  • Use session tokens only from browser-based code.
  • Rotate API keys periodically and revoke unused keys — last_used_at on the list endpoint tells you which are dormant.
  • Never commit API keys to version control.