Skip to content

Developer Guide

Add document signing to your app. Two integration paths depending on your platform:

PathForSDKHow It Signs
Web Apps (OAuth)Websites using "Sign in with Flowsta"@flowsta/authAPI call — server signs via conductor
Desktop Apps (Vault IPC)Holochain or Tauri apps running alongside Vault@flowsta/holochainIPC call — Vault signs locally, user approves

Prerequisites

  1. Register your app at dev.flowsta.com to get a clientId
  2. Choose your SDK:
    • Web apps: npm install @flowsta/auth
    • Desktop Holochain apps: npm install @flowsta/holochain

Web Apps (OAuth)

Setup

typescript
import { FlowstaAuth, hashFile } from '@flowsta/auth';

const flowsta = new FlowstaAuth({
  clientId: 'your_client_id',
  redirectUri: 'https://your-app.com/callback',
  scopes: ['profile', 'sign'],  // Request signing permission
});

The sign scope means the user will see "This app wants to sign files on your behalf" in the consent screen.

Sign a File

typescript
// 1. Hash the file client-side (never uploaded)
const hash = await hashFile(file);

// 2. Sign the hash
const result = await flowsta.signFile({
  fileHash: hash,
  intent: 'authorship',
  contentRights: {
    license: 'cc-by',
    aiTraining: 'not_allowed',
    contactPreference: 'allow_contact_requests',
  },
});

// 3. Use the result
console.log(result.action_hash);  // DHT record reference
console.log(result.agent_pub_key); // Signer's public key

The signature is committed to the Holochain DHT immediately. Anyone can verify it at flowsta.com/sign-it by dropping the same file.

Batch Sign Multiple Files

typescript
const hashes = await Promise.all(files.map(f => hashFile(f)));

const result = await flowsta.signBatch({
  files: hashes.map(h => ({ fileHash: h })),
  sharedMetadata: {
    intent: 'authorship',
    aiGeneration: 'none',
    contentRights: {
      license: 'all-rights-reserved',
      aiTraining: 'not_allowed',
    },
  },
});

console.log(`Signed ${result.signed} files, ${result.failed} failed`);

Maximum 100 files per batch. Each file gets its own signature on the DHT.

Verify a File

typescript
const result = await flowsta.verifyFile(hash);

if (result.count > 0) {
  result.signatures.forEach(sig => {
    console.log(`Signed by: ${sig.signer_did || sig.signer}`);
    console.log(`License: ${sig.content_rights?.license}`);
    console.log(`AI Training: ${sig.content_rights?.ai_training}`);
    console.log(`Revoked: ${sig.revoked}`);
  });
}

Verification is a public endpoint — no authentication required. Authenticated requests with the verify scope get higher rate limits.

Check Content Rights

typescript
const rights = await flowsta.getContentRights(hash);

if (rights.signed) {
  console.log(`${rights.signerCount} signer(s)`);
  rights.rights.forEach(r => {
    if (r.aiTraining === 'not_allowed') {
      console.log('Do not use for AI training');
    }
  });
}

OAuth Scopes

ScopePurposeRequired For
signSign files on behalf of the usersignFile(), signBatch(), revocation
verifyHigher rate limits for verificationverifyFile(), getContentRights() (optional — public endpoints work without auth)

Desktop Apps (Vault IPC)

For Holochain apps or Tauri desktop apps running alongside Flowsta Vault. Signing happens locally via IPC — the user approves in Vault.

Setup

bash
npm install @flowsta/holochain

Check if Vault is Available

typescript
import { getSigningStatus } from '@flowsta/holochain';

const status = await getSigningStatus();
if (status.available) {
  // Vault is running, unlocked, and ready to sign
  showSignButton();
} else if (status.vaultRunning && !status.vaultUnlocked) {
  showMessage('Please unlock Flowsta Vault to sign files');
} else {
  showMessage('Install Flowsta Vault to sign files');
}

Sign a File

typescript
import { signDocument } from '@flowsta/holochain';

const result = await signDocument({
  clientId: 'your_client_id',       // From dev.flowsta.com
  appName: 'ArtStudio',             // Shown in Vault approval dialog
  fileHash: 'a7f3b9c1e2d4...',      // SHA-256 hex (64 chars)
  label: 'Illustration.png',        // Optional: shown in approval dialog
  intent: 'authorship',
  contentRights: {
    license: 'cc-by',
    aiTraining: 'not_allowed',
    contactPreference: 'allow_contact_requests',
  },
});

console.log(result.signature);    // Base64 Ed25519 signature
console.log(result.agentPubKey);  // uhCAk... format
console.log(result.actionHash);   // DHT action hash

The user sees an approval dialog in Vault showing your app name, the file label, and the metadata. If they approve, Vault signs the hash with their Ed25519 key and commits the signature to the local Holochain conductor. The signature gossips to the server DHT automatically.

Handle Errors

typescript
import { signDocument, VaultNotFoundError, VaultLockedError, UserDeniedError } from '@flowsta/holochain';

try {
  const result = await signDocument({ ... });
} catch (e) {
  if (e instanceof VaultNotFoundError) {
    // Vault is not running — prompt user to open it
  } else if (e instanceof VaultLockedError) {
    // Vault is locked — prompt user to unlock
  } else if (e instanceof UserDeniedError) {
    // User rejected the signing request
  }
}

Key Differences from OAuth Path

OAuth (Web)Vault IPC (Desktop)
Where signing happensServer conductorLocal Vault conductor
User approvalImplicit (OAuth consent)Explicit dialog per request
File integrity checksNot availableVault runs 6 checks automatically
Perceptual hashingNot availableVault generates automatically
Gossip delayNone (direct to server)Minutes (gossip from local to server)
Offline supportNoYes (signature stored locally, gossips when online)

Shared Features

These work the same regardless of which path you use.

Deep Linking to Verification

Link directly to the verification page for a specific file:

https://flowsta.com/sign-it/?hash=a7f3b9c1e2d4...

The page auto-verifies and shows results.

Rate Limits

EndpointLimit
Verification (GET /verify)30 requests/minute per IP
File upload verification (POST /verify-file)30 requests/minute per IP
Contact relay (POST /contact)3 requests/hour per IP
Signing (POST /sign, /sign-batch)Per developer tier

Next Steps

Documentation licensed under CC BY-SA 4.0.