Authentication
All authentication-related endpoints, including SIWE login, token management, interactive agent connections, and MCP OAuth 2.1 flows.
SIWE Authentication
POST /auth/siwe/nonce
Generate a nonce for SIWE authentication.
Authentication: Public
Request Body:
{
"walletAddress": "0x1234567890123456789012345678901234567890"
}
Response:
{
"nonce": "random-nonce-string"
}
POST /auth/siwe/verify
Verify a SIWE signature and issue tokens.
Authentication: Public
Request Body:
{
"message": "SIWE message string",
"signature": "0x..."
}
Response:
{
"accessToken": "jwt-access-token",
"refreshToken": "jwt-refresh-token",
"user": {
"id": "user-id",
"ethereumAddress": "0x1234567890123456789012345678901234567890"
}
}
Token Management
POST /auth/refresh
Refresh an access token using a refresh token.
Authentication: Public
Request Body:
{
"refreshToken": "jwt-refresh-token"
}
Response:
{
"accessToken": "new-jwt-access-token",
"refreshToken": "new-jwt-refresh-token"
}
POST /auth/logout
Revoke a single refresh token.
Authentication: JWT
Request Body:
{
"refreshToken": "jwt-refresh-token"
}
Response: 204 No Content
POST /auth/logout-all
Revoke all refresh tokens for the current user across all devices.
Authentication: JWT
Response: 204 No Content
GET /auth/validate
Validate a JWT token.
Authentication: JWT
Response:
{
"valid": true,
"user": {
"id": "user-id",
"ethereumAddress": "0x1234567890123456789012345678901234567890"
}
}
GET /auth/me
Get current user information.
Authentication: JWT
Response:
{
"id": "user-id",
"ethereumAddress": "0x1234567890123456789012345678901234567890"
}
Interactive Agent Connection
These endpoints implement the interactive authentication flow, allowing AI agents to obtain API credentials by directing users to authenticate through the Nava UI.
POST /auth/connect/initiate
Generate a connection code and auth URL.
Authentication: Public
Response:
{
"code": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
"authUrl": "https://testnet.navalabs.dev/connect?code=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
}
| Field | Type | Description |
|---|---|---|
code | string | 32-character hex connection code (128 bits of entropy) |
authUrl | string | URL to present to the user for authentication |
Status Codes: 200 Success, 429 Rate limit exceeded (10 req/min)
GET /auth/connect/status
Poll connection status.
Authentication: Public
Query Parameters: code (required). The connection code from the initiate response.
Response (pending):
{
"status": "pending"
}
Response (ready, returned once, then code is consumed):
{
"status": "ready",
"apiKey": "nava_live_abc123def456...",
"walletAddress": "0x1234567890123456789012345678901234567890"
}
The API key is returned exactly once. After the first successful "ready" response, subsequent polls return 410 Gone.
The provisioned API key has scopes: transactions:create:own, transactions:approve:own, transactions:read:own.
Status Codes: 200 Success, 404 Code not found, 410 Expired or consumed, 429 Rate limit (30 req/min)
POST /auth/connect/approve
Approve a connection and provision an API key.
Authentication: JWT
Request Body:
{
"code": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
}
Response:
{
"success": true
}
Status Codes: 200 Approved, 400 Not in pending state, 401 JWT required, 404 Not found, 410 Expired, 429 Rate limit (5 req/min)
MCP OAuth 2.1
MCP Endpoint
POST|GET|DELETE /mcp
MCP Streamable HTTP transport endpoint.
Authentication: OAuth 2.1 Bearer token (preferred) or API key (legacy)
- POST: Send MCP messages (initialize, tool calls, etc.)
- GET: Open SSE stream for server notifications
- DELETE: Terminate an MCP session
Headers:
Authorization: Bearer <access_token>(OAuth 2.1, preferred)x-api-key: <api-key>(legacy fallback)Mcp-Session-Id: <session-id>(required after initialization)Accept: application/json, text/event-stream
Available MCP Tools:
| Tool | Description |
|---|---|
requestVerification | Submit a blockchain transaction for verification |
checkVerificationStatus | Check the verification status of a submitted transaction |
OAuth 2.1 Discovery
GET /.well-known/oauth-protected-resource
OAuth Protected Resource Metadata (RFC 9728).
Authentication: Public
Response:
{
"resource": "https://internal.navalabs.dev/api/mcp",
"authorization_servers": ["https://internal.navalabs.dev/api"],
"scopes_supported": [
"transactions:create:own",
"transactions:approve:own",
"transactions:read:own"
],
"resource_name": "Nava MCP Server"
}
GET /.well-known/oauth-authorization-server
OAuth Authorization Server Metadata (RFC 8414).
Authentication: Public
OAuth 2.1 Client Registration
POST /oauth/register
Dynamic Client Registration (RFC 7591).
Authentication: Public
Request Body:
{
"redirect_uris": ["http://127.0.0.1:3000/callback"],
"client_name": "My MCP Client",
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "client_secret_post"
}
Response (201):
{
"client_id": "nava_mcp_a1b2c3d4e5f6...",
"client_secret": "raw-secret-shown-once",
"client_id_issued_at": 1700000000,
"redirect_uris": ["http://127.0.0.1:3000/callback"],
"client_name": "My MCP Client",
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "client_secret_post"
}
OAuth 2.1 Authorization Flow
GET /oauth/authorize
OAuth Authorization Endpoint. Redirects to the Nava UI consent page.
Query Parameters: response_type (must be "code"), client_id, redirect_uri, code_challenge, code_challenge_method, state, scope, resource
GET /oauth/session-info
Get OAuth session details for the consent page.
Query Parameters: session (required)
POST /oauth/approve
Approve an OAuth session after the user authenticates via SIWE.
Authentication: JWT
Request Body:
{
"sessionId": "uuid-session-id"
}
Response:
{
"redirectUrl": "http://127.0.0.1:3000/callback?code=AUTH_CODE&state=STATE"
}
OAuth 2.1 Token Exchange
POST /oauth/token
OAuth Token Endpoint. Supports authorization_code and refresh_token grants.
Response:
{
"access_token": "jwt-access-token",
"token_type": "bearer",
"expires_in": 900,
"refresh_token": "new-refresh-token",
"scope": "transactions:create:own transactions:approve:own transactions:read:own"
}
Access tokens are JWTs with a 15-minute expiry. Refresh tokens rotate on each use with a 30-day expiry.