Skip to content

Authentication

OpenTusk uses three layers of authentication depending on what you’re doing: accounts for identity, API keys for programmatic access, and Sui private keys for on-chain encryption operations. Invite codes tie all three together for agent onboarding.

Sign up at app.opentusk.ai or from the CLI. All new signups require an access code during the early access period.

Go to app.opentusk.ai/signup. You can pass an access code via URL parameter:

https://app.opentusk.ai/signup?code=YOURCODE

You can also sign up with Google via Sui zkLogin — the same access code requirement applies.

Sign in at app.opentusk.ai with email/password or Google OAuth. The web app uses short-lived JWT access tokens (15 min) with refresh tokens (30 days) — this is handled automatically.

Refresh tokens use family-based reuse detection: if a token is reused after rotation, the entire token family is revoked to prevent session hijacking.

The web app authenticates via custom JWTs:

TokenLifetimeTransport
Access token15 minutesAuthorization: Bearer header (HS256 JWT)
Refresh token30 daysPOST /api/auth/refresh to rotate

When the access token expires, the web app silently refreshes it using the refresh token. If the refresh token is expired or revoked, the user is logged out.

The web app supports two Google-based flows, both starting from GET /api/auth/google or GET /api/auth/google/zklogin to obtain a Google OAuth authorization URL.

Plain Google OAuthPOST /api/auth/google/callback

Used for sign-up and sign-in when the user doesn’t want an on-chain identity yet. The server exchanges the authorization code for ID and access tokens, finds or creates a user record, and issues OpenTusk JWTs. No Sui keypair is derived.

Google + Sui zkLoginPOST /api/auth/google/zklogin-auth (combined endpoint), or the two-step pair POST /google/zklogin-tokenPOST /google/zklogin-auth.

zkLogin derives a Sui address from a Google account using zero-knowledge proofs, so signing in with Google also unlocks shared-vault access without a separately-managed wallet. The user’s suiAddressSource is set to 'zklogin' (vs 'external' for addresses linked via link-sui).

The ZK prover used depends on the network:

NetworkProver
Mainnet (OPENTUSK_ENV=production)EnokiVITE_ENOKI_API_KEY required, baked into the web bundle
Testnet (OPENTUSK_ENV=development)prover-dev.mystenlabs.com (Mysten’s dev prover)

A network/prover mismatch will silently produce ZK proofs the on-chain verifier rejects — see Access Control Contract for the deployed verifier.

Both flows are token-based — the server emails a single-use token that must be POSTed back within its expiry window.

EndpointPurpose
POST /api/auth/forgot-passwordRequest a password-reset email. Body: { email }. Always returns 200 (does not reveal account existence). Rate-limited per IP.
POST /api/auth/reset-passwordComplete a password reset. Body: { token, newPassword }. Token is from the email link.
POST /api/auth/verify-emailMark an email as verified. Body: { token }. Token is from the verification email sent at signup.
POST /api/auth/resend-verificationRe-send the verification email. Body: { email }. Rate-limited per IP.
POST /api/auth/check-access-codeValidate an access code client-side before submitting the signup form. Body: { code }.

Email verification is not required to access most of the API — uploads, downloads, and vault operations work for unverified accounts. Verification is required for billing operations (Stripe checkout, plan changes) so we can recover account access if a credit card is misused.

API keys are the primary way to authenticate with the OpenTusk API from the CLI, SDK, scripts, CI pipelines, and MCP servers. Every API call (outside of web sessions) uses an API key.

  1. You create a key — the full key (otk_...) is shown once
  2. The server stores only a SHA-256 hash of the key
  3. On each request, the server hashes the incoming key and looks it up by hash
  4. The raw key cannot be retrieved later — if you lose it, create a new one

Pass the key in the Authorization header on every request:

Terminal window
curl https://api.opentusk.ai/api/files \
-H "Authorization: Bearer otk_your_key"

Or in the SDK:

import { OpenTuskClient } from '@opentusk/sdk';
const opentusk = new OpenTuskClient({ apiKey: 'otk_your_key' });

Or set it as an environment variable for the CLI:

Terminal window
export OPENTUSK_API_KEY=otk_your_key
opentusk ls

Go to Settings > API Keys > Create API Key at app.opentusk.ai.

PropertyDescription
PrefixAll keys start with otk_
ScopesOptional — restrict to specific operations (e.g., files:read)
Vault restrictionsOptional — limit access to specific vault IDs
ExpiryOptional — auto-expire after N days
Sui addressOptional — binds a Sui address for shared vault encryption
RevocationImmediate — sets revoked_at, all subsequent requests fail
Terminal window
opentusk account api-keys list # Find the key ID
opentusk account api-keys revoke <key-id>

Revocation is instant. Any in-flight requests using the key will fail.

Sui private keys are used for on-chain operations — specifically, encrypting and decrypting files in shared vaults using the SEAL protocol. They are separate from API keys and serve a different purpose.

Shared vaults use SEAL (Sui Encryption with Access Lists) — an identity-based encryption scheme where access is controlled by Sui addresses on the blockchain. To encrypt or decrypt files in a shared vault, you need a Sui Ed25519 private key that corresponds to an address listed on the vault’s on-chain allowlist.

OperationRequires API keyRequires Sui key
Upload to public vaultYesNo
Upload to shared vaultYesYes (SEAL encrypt)
Download from public vaultYesNo
Download from shared vaultYesYes (SEAL decrypt)
Create/manage vaultsYesYes (signs on-chain tx)
Grant/revoke vault accessYesYes (signs on-chain tx)
List files, account info, etc.YesNo
Terminal window
opentusk setup
# The wizard offers to generate a Sui keypair and link it to your account
ContextStorageNotes
CLI config~/.config/opentusk/config.jsonStored by opentusk setup or account setup-sui
Environment variableOPENTUSK_SUI_PRIVATE_KEYTakes precedence over config
MCP server configEmbedded in .mcp.json / agent configWritten by opentusk mcp install-config
Web appBrowser wallet (Sui Wallet, Phantom)Never touches the server

The Sui private key never leaves your machine. The server only knows your Sui address (public), not the private key.

After setting up a Sui key, you need to link its public address to your OpenTusk account. This tells the server which Sui address is yours, so it can include you on vault allowlists.

Terminal window
opentusk account link-sui 0x1234...abcd

The opentusk setup wizard does this automatically when generating a keypair.

Invite codes combine all three authentication layers into a single onboarding command for AI agents. One code sets up an API key, a Sui keypair, and the address link — all scoped to the owner’s account.

Owner Agent
│ │
├─ opentusk invite create │
│ → gets otinv_abc123... │
│ │
├─ shares code with agent ────────►│
│ ├─ opentusk login --invite-code otinv_...
│ │ ├─ Generates Sui Ed25519 keypair
│ │ ├─ Redeems code → receives API key
│ │ └─ Stores API key + Sui key in config
│ │
├─ opentusk vault members add │
│ <vault> <agent-sui-address> │
│ ├─ Can now encrypt/decrypt in shared vault
Terminal window
# Basic — 1 hour expiry
opentusk invite create --name "my-agent"
# With scope and vault restrictions
opentusk invite create --name "reader" \
--scopes files:read \
--vaults vault-id-1,vault-id-2 \
--expires 24
# Manage codes
opentusk invite list
opentusk invite revoke <invite-code-id>

Codes are single-use and short-lived (default 1 hour, max 72 hours). Like API keys, the full code is shown once — the server stores a SHA-256 hash.

When an agent redeems an invite code, its API key gets a Sui address that differs from the account owner’s. This automatically classifies it as an agent key with restricted permissions.

OwnerAgent
Upload / download / list filesYesYes
Create / list / manage foldersYesYes
List vaults and vault detailsYesYes
Soft-delete files (trash)YesYes
Create / update / delete vaultsYesNo
Create / revoke API keysYesNo
Add / remove vault membersYesNo
Billing and plan changesYesNo
Manage webhooksYesNo

The GET /api/account endpoint returns accessLevel: "owner" or "agent" so clients can adapt their behavior.

See Invite Codes for the full guide — Sui key locking, managing multiple agents, and revoking access.

Authentication failures return 401 Unauthorized:

{
"error": "Unauthorized"
}

This applies to missing keys, invalid keys, revoked keys, and expired JWTs.