JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 61
  • Score
    100M100P100Q93266F
  • License MIT

Intent verification infrastructure for agents and human-authorized actions.

Package Exports

  • @fortsignal/sdk
  • @fortsignal/sdk/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@fortsignal/sdk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@fortsignal/sdk

The official TypeScript SDK for FortSignal — intent verification infrastructure for agents and human-authorized actions.

Full documentation: fortsignal.com/docs

What it does

FortSignal verifies that the exact parameters a user or agent approved are the same parameters that execute. Every sensitive action gets a fresh hardware-signed approval — cryptographically bound to the action, amount, recipient, and any other fields you define.

Installation

npm install @fortsignal/sdk

You'll also need the WebAuthn browser library for your frontend:

npm install @simplewebauthn/browser

Get an API key

Sign up at fortsignal.com/signup. You'll get a fs_live_... key immediately after checkout.


Human Flow

Step 1 — Initialize the client (server-side)

import { FortSignal } from '@fortsignal/sdk'

const client = new FortSignal({ apiKey: process.env.FORTSIGNAL_API_KEY })

Step 2 — Register a user's passkey (one time per user)

Call this when the user sets up their account or enables high-security actions.

// Server: start registration
const options = await client.register.start({
  userId: 'user_123',
  username: 'alice@example.com',
})

// Browser: prompt the user to create a passkey
import { startRegistration } from '@simplewebauthn/browser'
const attestation = await startRegistration({ optionsJSON: options })

// Server: complete registration
await client.register.complete({
  userId: 'user_123',
  challenge: options.challenge,
  attestation,
})

Step 3 — Require approval before a sensitive action

// Server: start a challenge before the action executes
const { challengeId, challenge } = await client.challenge.start({
  userId: 'user_123',
  action: 'transfer',
  amount: 500,
  recipient: 'bob@example.com',
  from: 'alice@example.com',
  metadata: { orderId: 'ord_123' }, // optional — any JSON object
})

// Browser: prompt the user to sign with their passkey
import { startAuthentication } from '@simplewebauthn/browser'
const assertion = await startAuthentication({ optionsJSON: { challenge, ... } })

// Server: verify the signature
const result = await client.challenge.verify({ challengeId, assertion })

if (result.allowed) {
  // result.signalId — store this as your audit receipt
  await executeTransfer()
} else {
  // result.reason — why it was denied
  // 'policy_expired' | 'action_not_allowed' | 'amount_exceeds_policy'
  // 'recipient_not_allowed' | 'biometric_required' | 'parameters_tampered'
  throw new Error(result.reason)
}

Agent Flow

Step 1 — Register an agent's public key (one time per agent)

Generate an Ed25519 keypair for your agent and register the public key.

const { agentId } = await client.agent.register({
  agentId: 'my-agent-01',        // your identifier — alphanumeric, dash, underscore, max 64 chars
  publicKey: agentPublicKeyBase64, // Ed25519 public key, base64url encoded
})
// Store agentId — you'll need it to issue a delegation from the dashboard

Step 2 — Issue a delegation (dashboard)

Go to your FortSignal dashboard and issue a delegation for the agent. Set the scope — allowed actions, max amount per action, allowed recipients, and expiry. Copy the delegationId and store it with your agent.

Delegation management requires owner authentication and cannot be done via API key. This is intentional — a compromised API key cannot grant or revoke agent permissions.

Step 3 — Verify each agent action

The agent signs a nonce with its Ed25519 private key before each action.

const result = await client.agent.verify({
  delegationId: 'del_abc123',
  action: 'transfer',
  amount: 250,
  recipient: 'acct_456',
  signature: agentSignature,  // Ed25519 signature over the nonce
  nonce: challengeNonce,
})

if (result.allowed) {
  // result.signalId — audit receipt
  await executeAction()
} else {
  // result.reason — scope exceeded, delegation expired, signature invalid, etc.
}

Error Handling

Deny decisions are not errors — they come back in the response body:

const result = await client.challenge.verify({ challengeId, assertion })

if (!result.allowed) {
  // result.reason — why it was denied:
  // 'policy_expired' | 'action_not_allowed' | 'amount_exceeds_policy'
  // 'recipient_not_allowed' | 'biometric_required' | 'parameters_tampered'
  console.error(result.reason)
}

HTTP errors (bad API key, rate limit, server error) throw a FortSignalError:

import { FortSignal, FortSignalError } from '@fortsignal/sdk'

try {
  const result = await client.challenge.start({ ... })
} catch (err) {
  if (err instanceof FortSignalError) {
    console.error(err.code)   // e.g. 'invalid_api_key'
    console.error(err.status) // e.g. 401
  }
}

API Reference

client.register

Method Description
register.start({ userId, username }) Begin passkey registration
register.complete({ userId, challenge, attestation }) Complete passkey registration

client.challenge

Method Description
challenge.start({ userId, action, amount, recipient, from, metadata? }) Start a challenge
challenge.verify({ challengeId, assertion }) Verify the signed assertion

client.agent

Method Description
agent.register({ agentId, publicKey }) Register an agent's Ed25519 public key
agent.verify({ delegationId, action, amount, recipient, signature, nonce }) Verify an agent-signed action

Requirements

Full Documentation

fortsignal.com/docs