Skip to main content

Authentication

There are several ways to authenticate with Nava. Choose based on how you want to handle credentials and how tightly you want to integrate.

Authentication Modes

ModeHow It WorksBest For
Non-interactive (API Key)Obtain a Nava API key ahead of time via the Nava UI and configure it locally. The agent never needs to prompt the user for credentials.SDK, MCP (local), skill (non-interactive)
Headless Wallet (SIWE)The agent signs a SIWE message with its wallet, exchanges it for JWT tokens, then creates a session API key via POST /user-api-keys. No Nava UI interaction required.Autonomous agents with signing capability
Interactive (OAuth)The MCP client handles OAuth with the Nava authorization server. The user logs in through the Nava UI in their browser.MCP (remote), zero-setup for end users
Interactive (Code-based)The agent requests a short-lived login code, then prompts the user to visit the Nava UI and enter the code. Once authenticated, the agent receives an API key for the session.Any agent with shell access, no pre-provisioned key

Non-Interactive Setup

  1. Sign up at Nava UI and create an API key.
  2. Store the key as NAVA_API_KEY and your wallet address as WALLET_ADDRESS in your environment.

Headless Wallet (SIWE → API Key Bootstrap)

Use this when the runtime can sign messages (local wallet lib, hardware signer, or wallet MCP/tool adapter).

import { createClientFromWallet } from '@navalabs/sdk';

const signer = {
async getAddress() {
return wallet.address;
},
async signMessage(message: string) {
return wallet.signMessage(message);
},
};

const { client, apiKey, walletAddress } = await createClientFromWallet({
signer,
baseUrl: 'https://internal.navalabs.dev/api',
domain: 'testnet.navalabs.dev',
uri: 'https://internal.navalabs.dev/api',
chainId: 11155111,
apiKeyName: 'agent-session',
});

Bootstrap sequence:

  1. POST /auth/siwe/nonce
  2. Build SIWE message with domain, address, statement, uri, version: "1", chainId, nonce, issuedAt
  3. Sign the exact SIWE message string
  4. POST /auth/siwe/verify with { message, signature }
  5. POST /user-api-keys with Authorization: Bearer <accessToken>
  6. Use returned API key for all subsequent SDK/MCP/API calls

Lower-level helpers are exported for external wallet toolchains: prepareSiweAuthentication, verifySiweAuthentication, createUserApiKey, and buildSiweMessage.

Interactive (OAuth): MCP Remote

The MCP client handles this automatically. See MCP Server (Remote) for setup.

MCP Client                Nava MCP Server              Nava UI (Browser)
│ │ │
├── connect ─────────────────►│ │
│◄── OAuth challenge ────────┤ │
│── open browser ────────────┼───────────────────────────►│
│ │◄── user logs in & grants ──┤
│◄── authenticated ──────────┤ │
├── requestVerification ────►│ │
│◄── result ─────────────────┤ │

Interactive (Code-Based)

For agents that can run shell commands but don’t have a pre-provisioned key.

Step 1: Initiate authentication

curl -s -X POST "https://internal.navalabs.dev/api/auth/connect/initiate" \
-H "Content-Type: application/json"

Response contains:

  • code: a 32-character hex connection code (expires after 10 minutes)
  • authUrl: a URL for the user to visit

Present the authUrl to the user and ask them to open it in their browser, sign in, and approve the connection.

Step 2: Poll for API key

curl -s -X GET "https://internal.navalabs.dev/api/auth/connect/status?code=<code>" \
-H "Content-Type: application/json"

Poll every 3-5 seconds. When the user completes authentication:

  • status: "ready"
  • apiKey: the provisioned API key (returned exactly once; subsequent polls return 410 Gone)
  • walletAddress: the authenticated wallet address

Store these for the remainder of the session.

API Key Types

The service supports multiple API key types:

  • USER keys: User-specific operations (:own scopes). Created via POST /user-api-keys (requires JWT auth).
  • ADMIN keys: Administrative/agent operations (:any scopes).
  • ORION keys: Arbiter/orion approval operations.

Scopes

  • transactions:create:own: Create transactions for own account
  • transactions:create:any: Create transactions for any account
  • transactions:approve:own: Approve own transactions
  • transactions:read:own: Read own transactions