Skip to content

Authentication

ModeUse caseHow
OAuthInteractive use (Claude, Cursor)Client triggers a login flow; credentials never leave Adva
API KeyHeadless, scripts, automationMint a key in Adva, pass it as a header

Pick OAuth if a human is sitting at the keyboard. Pick API key for scheduled jobs, CI pipelines, or any flow without an interactive browser.

When a client is configured without an X-API-Key header, it triggers OAuth on first tool call.

  1. The client opens a browser to https://mcp.getadva.ai/authorize (or https://mcp-staging.getadva.ai/authorize on staging).
  2. Adva’s MCP server 302-redirects the browser to https://app.getadva.ai/oauth/authorize?client_id=…&redirect_uri=…&state=… (on staging: https://staging.getadva.ai/oauth/authorize?…). The MCP server never asks for your password — that part is handled by Adva’s web app using your existing session.
  3. If you’re already signed into app.getadva.ai, you go straight to the consent screen. Otherwise you see the normal Adva login first, then land on the consent screen after signing in.
  4. You click Allow access. Adva mints a single-use authorization code (POST /api/v1/oauth/authorization-codes) and redirects your browser back to the MCP server with ?code=&state=.
  5. The MCP server exchanges the code at POST /api/v1/oauth/token for an access token + refresh token and hands control back to your MCP client. The tokens are stored by the client; you won’t see this step.

A small card titled Authorize MCP client with:

  • The client_id of the MCP client that’s asking (for example claude-desktop).
  • A Signed in as panel showing your Adva email.
  • A short scope description: “Read and modify data in your business on your behalf” and “Access the same resources you can access.”
  • Two buttons: Cancel and Allow access.

There’s no business picker on this screen. The token is bound to whichever business is active in your Adva web session at the moment you click Allow. See Key Scope: One Business below.

Your Adva account must be linked to a business and an account before OAuth will succeed. If you see a 403 “Account not linked” error, or Adva redirects you to /no-account, ask an admin to provision access — no amount of logging in will fix it client-side.

TokenLifetimeNotes
Authorization code10 minutesSingle-use, consumed atomically during /oauth/token exchange
Access token1 hourSelf-contained JWT; sent as Authorization: Bearer <jwt>
Refresh token30 daysStored hashed server-side; used to mint new access tokens

Refresh is transparent. Your MCP client silently exchanges the refresh token for a fresh 1-hour access token as needed — you won’t see a second browser prompt until the refresh token itself expires (30 days).

Role changes (promotions, demotions, business removals) take effect within at most one refresh cycle. Every refresh re-reads your current account_role and business_role from the database before signing the new token.

There is no “Connected apps” UI in Adva today. If you need to cut off an MCP client’s access:

  • Short-term: wait out the access token’s 1-hour expiry. Access tokens are self-contained JWTs and don’t check a revocation list.
  • Immediate: contact support. Revoking the refresh token server-side kills the client’s ability to get new access tokens; the next refresh attempt will fail and the client will ask you to re-authorize.

A customer-facing Connected Apps page is planned but not shipped.

Use an API key whenever you want to skip the browser login entirely — for example, on a server, in a cron job, or inside a CI/CD pipeline.

  1. Sign in to https://app.getadva.ai and go to Settings → API Keys.
  2. Click Create API Key.
  3. Give it a name (e.g. "claude-desktop-ryan-laptop"), pick scopes (default import), and optionally set an expiry.
  4. Click Create. The raw key is displayed once — copy it immediately and store it securely. You will not be able to view it again.

The raw key starts with adva_k_ and looks like adva_k_live_abc123....

Pass the key in either of these headers. Header names are case-insensitive.

X-API-Key: adva_k_your_key_here

or:

Authorization: ApiKey adva_k_your_key_here

Do not use Authorization: Bearer ... for an API key — Bearer is reserved for OAuth JWTs. Mixing them up causes a 401.

Every credential is bound to exactly one business — this is true for both OAuth tokens and API keys.

  • API key: bound at mint time to the business the key was created in.
  • OAuth token: bound to whichever business is active in your Adva web session at the moment you click Allow access on the consent screen. POST /api/v1/oauth/refresh reuses the original business — refresh does not switch it.

To target a different business from MCP:

  • OAuth: open app.getadva.ai, use the business switcher in the top bar to change your active business, then re-authorize the MCP client (for example, by reconnecting it in Claude Desktop / Cursor). The next run mints a fresh token bound to the new business.
  • API key: mint a separate key in each business.

The list_businesses MCP tool is a read-only orientation tool — it tells you which businesses your user can see, but it does not change the token’s binding. start_csv_import and the other import tools always write to the business the token is bound to.

In Settings → API Keys, click the trash icon next to a key and confirm. Revoked keys are dead permanently; any client still using them will start getting 401s immediately.