Skip to main content

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}