NCP Auth for Agents
This page is written for coding agents implementing NCP integrations in other apps.
Mechanical Recipe
- Build a valid NCP trigger object.
- Serialize it once:
rawBody = JSON.stringify(trigger). - Use that exact raw body as the HTTP request body.
- Create an ISO timestamp.
- Sign
timestamp + "." + rawBodywith HMAC-SHA256 using the NCP connection token. - Send
Authorization,X-NCP-Timestamp,X-NCP-Signature, andX-NCP-Event-Id.
Rules
- Do not sign a different JSON string than the one you send.
- Do not put the token in the JSON payload.
- Do not log the bearer token or signature.
- Use server-side secret storage, not browser local storage.
- Use a stable event ID from the source system when possible.
- Retry with the same event ID so receivers can suppress duplicates.
- Treat HTTP 409 duplicate as success.
- Treat HTTP 401 as reconnect required.
- Treat HTTP 403 as source or event-type scope mismatch.
Node / TypeScript
import { createHmac, randomUUID } from "node:crypto";
function base64url(buffer: Buffer) {
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}
export function signNcpRequest(token: string, rawBody: string, timestamp = new Date().toISOString()) {
const signature = base64url(createHmac("sha256", token).update(`${timestamp}.${rawBody}`).digest());
return {
timestamp,
signature: `sha256=${signature}`
};
}
export async function sendNcpTrigger(input: {
endpoint: string;
token: string;
trigger: unknown;
eventId?: string;
}) {
const rawBody = JSON.stringify(input.trigger);
const { signature, timestamp } = signNcpRequest(input.token, rawBody);
const eventId = input.eventId ?? randomUUID();
const response = await fetch(input.endpoint, {
method: "POST",
headers: {
"authorization": `Bearer ${input.token}`,
"content-type": "application/json",
"x-ncp-event-id": eventId,
"x-ncp-signature": signature,
"x-ncp-timestamp": timestamp
},
body: rawBody
});
if (response.status === 409) return { duplicate: true, ok: true };
if (response.status === 401) throw new Error("NCP token rejected. Ask the user to reconnect NerveOS System.");
if (response.status === 403) throw new Error("NCP token scope does not allow this source or event type.");
if (!response.ok) throw new Error(`NCP request failed: ${response.status}`);
return response.json();
}Python
import base64
import hashlib
import hmac
import json
import uuid
from datetime import datetime, timezone
import requests
def base64url(raw: bytes) -> str:
return base64.urlsafe_b64encode(raw).decode("utf-8").rstrip("=")
def sign_ncp_request(token: str, raw_body: str, timestamp: str | None = None):
timestamp = timestamp or datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
digest = hmac.new(token.encode("utf-8"), f"{timestamp}.{raw_body}".encode("utf-8"), hashlib.sha256).digest()
return timestamp, f"sha256={base64url(digest)}"
def send_ncp_trigger(endpoint: str, token: str, trigger: dict, event_id: str | None = None):
raw_body = json.dumps(trigger, separators=(",", ":"))
timestamp, signature = sign_ncp_request(token, raw_body)
event_id = event_id or str(uuid.uuid4())
response = requests.post(
endpoint,
data=raw_body,
headers={
"authorization": f"Bearer {token}",
"content-type": "application/json",
"x-ncp-event-id": event_id,
"x-ncp-signature": signature,
"x-ncp-timestamp": timestamp,
},
timeout=10,
)
if response.status_code == 409:
return {"ok": True, "duplicate": True}
if response.status_code == 401:
raise RuntimeError("NCP token rejected. Ask the user to reconnect NerveOS System.")
if response.status_code == 403:
raise RuntimeError("NCP token scope does not allow this source or event type.")
response.raise_for_status()
return response.json()SummitOS Agent Prompt
You are adding NCP Auth v0.1 support to SummitOS.
Implement a per-expedition NerveOS System integration.
UI:
- In each expedition, add "Enable NerveOS System".
- Store NerveSynapse endpoint and NCP connection token server-side only.
- Let the user choose which expedition signals can fire.
Allowed event types for a mountain expedition:
- expedition.weather_window
- expedition.readiness_changed
- expedition.permit_deadline
- expedition.route_condition_warning
- expedition.partner_availability_conflict
Auth:
- POST valid NCP trigger JSON to the user's NerveSynapse endpoint.
- Use Authorization: Bearer ncp_live_...
- Sign the exact raw JSON body sent on the wire.
- X-NCP-Signature = sha256=base64url(hmac_sha256(token, timestamp + "." + rawBody))
- X-NCP-Timestamp = ISO timestamp
- X-NCP-Event-Id = stable source event ID
Error handling:
- 2xx: mark delivered.
- 409 duplicate: treat as already delivered.
- 401: disable integration and ask user to reconnect.
- 403: show permission/scope mismatch.
- 429 or 5xx: retry with backoff using the same X-NCP-Event-Id.
Privacy:
- Do not include private messages, raw GPS traces, health data, payment data, or secrets in the payload.
- Use context_refs to link back to SummitOS expedition details.