STACK
MENU
DOCS / SECURITY / AUTH FOR CLI, SDK, AND MCP

Authenticating STACK across CLI, SDK, and AI clients

Interactive clients use OAuth 2.1 with PKCE. Headless CI and service environments can use the operator's sk_live_* key when they cannot complete a browser flow, but the key carries operator-wide access.

From your terminal (CLI)

bash
npx @getstackrun/cli auth login

Opens a browser, asks you to approve the device, and stores a refresh token at ~/.stack/credentials.json with mode 0600. On Linux and macOS the CLI sets the file to mode 0600; on Windows it inherits the access controls on %USERPROFILE%\.stack.

Subsequent runs read the refresh token, exchange it for a one-hour access token, and rotate the refresh on use. npx @getstackrun/cli auth status shows the current sign-in state, while npx @getstackrun/cli auth logout revokes the refresh and clears the file.

From an MCP client

Add STACK as a remote MCP server with the URL below. The client starts the OAuth flow. Approve the requested scopes in your browser.

text
https://mcp.getstack.run/mcp

Use the client-specific integration guide when you need its exact command or settings path.

On the first call, the MCP server returns 401 Unauthorized with a WWW-Authenticate: Bearer resource_metadata=... header pointing at /.well-known/oauth-protected-resource. The MCP client picks that up, starts the OAuth flow, and stores the resulting tokens in its own credential store.

From your application code (SDK)

For interactive development:

typescript
import { Stack } from '@getstackrun/sdk';

const stack = new Stack(); // reads ~/.stack/credentials.json
const agents = await stack.agents.list();

For an enrolled agent runtime:

typescript
const stack = new Stack({ agent_id: 'agt_xxx' });
// First run: generates an Ed25519 keypair locally, runs proof-of-possession
// enrollment via /v1/agents/<id>/enroll. Private key is persisted to
// ~/.stack/agents/<agent_id>.json (mode 0600).
// Subsequent runs sign every API call with a fresh 60-second JWT.

See Agent Keys for enrollment, signing, replay protection, and rotation.

For CI environments where there is no browser

Set STACK_API_KEY from the CI provider's secret store. This is the operator API key, not a workload-scoped credential, so any process that can read it receives operator-level access.

bash
STACK_API_KEY=sk_live_... node my-agent.js

Token model

  • Access tokens: one-hour TTL. Bearer for API + MCP calls. EdDSA-signed JWT, audience-bound to stack:api or stack:mcp. Revoking the token family rejects them on the next STACK call.
  • Refresh tokens: 30-day TTL, rotated on every use. The live token is stored as a sha256 hash. A rotated parent keeps the exact successor in a KMS envelope for a fixed 60-second retry window.
  • Retry and reuse: concurrent retries receive one identical successor. A stale replay revokes the entire token family and records a critical security event in your audit log.

Security effect

An API key in your .env file or your CI secrets store is a credential that a reader can copy. OAuth stores a rotating refresh token in the user's credential store and issues one-hour access tokens. Refresh-token replay revokes the token family and records a security event.

Reduced risks

  • Interactive setup does not require a long-lived API key in source or MCP configuration.
  • Access tokens expire after one hour and remain revocable through their token family.
  • Refresh-token rotation detects stale-token replay.

Use OAuth for interactive clients. Use the operator API key only when a headless workload cannot complete that flow, and keep it out of agent prompts, source code and logs.

stack | Docs