Skip to main content

Authentication

Authentication​

OpenCap Stack supports three authentication methods. Choose the one that fits your use case.

MethodBest ForToken Lifetime
AINative SSOUsers who already have an AINative account7 days (refresh)
Email / PasswordStandard login, your own user base7 days (refresh)
Agent OnboardingAI agents, CI/CD, server-to-serverNon-expiring API key

All methods return a JWT Bearer token used in the Authorization header:

Authorization: Bearer <your-token>

AINative SSO​

If your users have AINative accounts, you can authenticate them against OpenCap Stack without a separate credential.

Send the user's AINative credentials to OpenCap Stack's proxy endpoint — no redirect required:

curl -X POST https://api.opencapstack.com/api/v1/auth/ainative-login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "ainative-password"
}'

Response:

{
"token": "eyJhbGci...",
"refreshToken": "eyJhbGci...",
"user": {
"id": "usr_abc123",
"email": "user@example.com",
"name": "Jane Doe",
"companyId": "co_xyz789"
}
}

This endpoint:

  1. Validates the credentials against the AINative /api/v1/auth/login API
  2. Fetches the AINative user profile via /api/v1/auth/me
  3. Provisions (or retrieves) a matching OpenCap Stack user
  4. Returns an OpenCap Stack JWT

Using the Token​

const response = await fetch('https://api.opencapstack.com/api/v1/auth/ainative-login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});

const { token } = await response.json();

// Store and use for subsequent requests
const data = await fetch('https://api.opencapstack.com/api/v1/stakeholders', {
headers: { Authorization: `Bearer ${token}` },
});

Next.js / React Integration​

// lib/authService.js
export async function loginWithAINative(email, password) {
const res = await fetch('/api/v1/auth/ainative-login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});

if (!res.ok) throw new Error('Authentication failed');

const { token, user } = await res.json();

// Set cookie for Edge Middleware auth
document.cookie = `session=${token}; path=/; secure; samesite=strict`;

return { token, user };
}
AINative OAuth 2.1 (Browser Redirect)

The full OAuth 2.1 PKCE browser redirect flow (/oauth/authorize) is available for registered redirect URIs. Contact AINative to add your domain to the allowlist. For most integrations the server-side proxy above is simpler and works immediately.


Email / Password​

Standard registration and login for users with their own OpenCap Stack accounts.

Register​

curl -X POST https://api.opencapstack.com/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe",
"email": "jane@startup.com",
"password": "securepassword123"
}'

Response:

{
"token": "eyJhbGci...",
"refreshToken": "eyJhbGci...",
"user": {
"id": "usr_abc123",
"email": "jane@startup.com",
"name": "Jane Doe"
}
}

Login​

curl -X POST https://api.opencapstack.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "jane@startup.com",
"password": "securepassword123"
}'

Refresh Token​

JWTs expire after 7 days. Use the refresh token to get a new one without re-authenticating:

curl -X POST https://api.opencapstack.com/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refreshToken": "eyJhbGci..." }'

Agent Onboarding​

The fastest path for AI agents, automation scripts, and server-to-server integrations. Zero human steps required.

curl -X POST https://api.opencapstack.com/api/v1/agents/onboard \
-H "Content-Type: application/json" \
-d '{
"agent_id": "my-cap-table-agent",
"agent_name": "Cap Table Automation",
"capabilities": [
"read:cap-table",
"write:stakeholders",
"write:equity",
"read:financials"
]
}'

Response:

{
"token": "eyJhbGci...",
"api_key": "ocs_live_abc123xyz...",
"company_id": "co_xyz789",
"agent_id": "my-cap-table-agent",
"capabilities": ["read:cap-table", "write:stakeholders", "write:equity", "read:financials"],
"provisioned_at": "2026-05-13T00:00:00Z"
}

Store both the token (JWT) and api_key — the API key doesn't expire and can be used directly.

Available Capability Scopes​

ScopeAccess
read:cap-tableStakeholders, share classes, equity grants, ownership percentages
write:stakeholdersCreate, update, delete stakeholders
write:equityIssue grants, update vesting schedules, create share classes
read:financials409A valuations, financial reports, fundraising data
write:documentsUpload and manage legal documents
read:analyticsReporting, dilution models, waterfall analysis
write:safe-notesCreate and update SAFE instruments
adminFull access — use only for trusted internal agents

Using the API Key​

## API key works as a Bearer token
curl https://api.opencapstack.com/api/v1/stakeholders \
-H "Authorization: Bearer ocs_live_abc123xyz..."
import requests

API_KEY = "ocs_live_abc123xyz..."
BASE_URL = "https://api.opencapstack.com/api/v1"

headers = {"Authorization": f"Bearer {API_KEY}"}

stakeholders = requests.get(f"{BASE_URL}/stakeholders", headers=headers).json()

Bring Your Own Auth​

If you're self-hosting OpenCap Stack, you can configure any JWT-compatible identity provider.

Set these environment variables:

JWT_SECRET=your-256-bit-secret
JWT_ISSUER=https://your-auth-provider.com # optional
JWT_AUDIENCE=opencapstack # optional

Your tokens must be signed RS256 or HS256 JWTs with a sub (user ID) claim. The middleware validates the signature and extracts the user from your existing user table.

For OIDC providers (Auth0, Clerk, Supabase Auth):

OIDC_ISSUER=https://your-tenant.auth0.com/
OIDC_AUDIENCE=https://api.opencapstack.com

See the Self-Hosting guide for full configuration.


Token Security​

  • Store tokens in httpOnly cookies or server-side sessions — never localStorage for production
  • The Next.js Edge Middleware validates the session cookie on every protected route
  • Refresh tokens are single-use and rotated on each refresh
  • Agent API keys can be revoked via DELETE /api/v1/agents/{agent_id}