Skip to main content
Core Concepts

SDK Authentication

Every SDK session (TypeScript's query(), Python's query() / QoderSDKClient) must be configured with one authentication method. A session can only use one:
Authentication methodIdentityUse case
Personal Access Token (PAT)A Qoder userScripts, CI, or host applications that need the user's permissions and data
Service AccountAn organization workloadBackend services, CI, and scheduled jobs that should not depend on a personal account
Local qodercli sessionThe currently signed-in userA developer workstation that is already signed in to Qoder

Use a PAT

A PAT represents a Qoder user. Use it for automation that must access that user's permissions and data.

Get a PAT

Create a PAT in Qoder Account Integrations:
  1. Sign in to Qoder.
  2. Open Account → Integrations.
  3. Choose the required permissions and expiry, then create the PAT.
  4. Copy the generated value immediately. It cannot be viewed again after the page is closed.
Create separate PATs for local scripts, CI, and production so they can be rotated or revoked independently.

Read a PAT from the environment

export QODER_PERSONAL_ACCESS_TOKEN="<your-qoder-personal-access-token>"
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Summarize the current workspace.',
  options: {
    auth: accessTokenFromEnv(),
  },
});
The function reads QODER_PERSONAL_ACCESS_TOKEN by default. To use a custom variable name:
auth: accessTokenFromEnv('MY_QODER_PAT')
If options.env and the process environment contain the same variable, the SDK uses the value from options.env.

Pass a PAT directly

When a trusted backend has already obtained a PAT, pass it directly:
import { accessToken, query } from '@qoder-ai/qoder-agent-sdk';

const token = await readTokenFromSecretManager();
const q = query({
  prompt: 'List the most recently modified files.',
  options: {
    auth: accessToken(token),
  },
});
The SDK does not refresh PATs. After a PAT becomes invalid, obtain a valid PAT and create a new SDK session.

Use a Service Account

Before you begin, ask a Qoder organization administrator to create a Service Account, grant the permissions your application needs, and generate a key. Store the key in a secret manager and provide it only to a trusted backend process or CI job.

Pass a Service Account key directly

When a trusted backend has already read the key from a secret manager, pass it directly:
import { query, serviceAccount } from '@qoder-ai/qoder-agent-sdk';

// Get the Service Account key from the host's secret manager adapter.
const serviceAccountKey = await readSecret('qoder-service-account-key');

const q = query({
  prompt: 'Explain the purpose of this project in one sentence.',
  options: {
    auth: serviceAccount({ serviceAccountKey }),
    cwd: process.cwd(),
  },
});
The caller passes the Key into the session via serviceAccount({ serviceAccountKey }) (TypeScript) / service_account(service_account_key=...) (Python). The SDK and qodercli obtain and refresh a short-lived Service Account Token (SAT) for the session.
secret manager
     |
     | Service Account Key
     v
caller reads the key
     |
     | serviceAccount({ serviceAccountKey })
     v
SDK starts qodercli and obtains a short-lived SAT
     |
     `----> authenticate session requests with the SAT
The SDK uses the key and SAT for the current session. The caller provides the key again when creating a new session. Read the key from a secret manager, and keep key literals out of source code, browser bundles, mobile applications, logs, and test snapshots.

Provide and refresh SATs from the host

If the host application embedding the SDK is responsible for exchanging SATs, use the fetch-callback form (TypeScript's serviceAccount({ fetchServiceAccountToken }), Python's service_account(fetch_service_account_token=...)). The Service Account Key stays in the host process, and qodercli receives SATs from the host callback. The callback is implemented by the host. qodercli invokes it whenever it needs a SAT; on each request, the host calls the Token exchange API and returns the fresh SAT from the response to qodercli.
qodercli
     |
     | request a SAT
     v
fetchServiceAccountToken callback in the SDK host
     |
     | call Token exchange with the host-managed Service Account key
     v
Qoder Token exchange
     |
     `----> return the short-lived SAT to qodercli
This complete example performs the exchange inside the host:
import {
  query,
  serviceAccount,
  type ServiceAccountTokenResult,
} from '@qoder-ai/qoder-agent-sdk';

// Get the Service Account key from the host's secret manager adapter.
const serviceAccountKey = await readSecret('qoder-service-account-key');
// Example: select the scopes used for model listing and inference.
const serviceAccountScopes = ['models.read', 'chat.completions'];

async function fetchServiceAccountToken(): Promise<ServiceAccountTokenResult> {
  const response = await fetch(
    'https://openapi.qoder.sh/api/v1/serviceToken/exchange',
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${serviceAccountKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        grant_type: 'client_credentials',
        audience: 'qoder',
        scope: serviceAccountScopes.join(' '),
        ttl_seconds: 3600,
      }),
    },
  );

  if (!response.ok) {
    throw new Error(`Unable to obtain a Qoder SAT: HTTP ${response.status}`);
  }

  const result = (await response.json()) as {
    access_token: string;
    expires_in?: number;
  };

  return {
    token: result.access_token,
    expiresAt:
      result.expires_in === undefined
        ? undefined
        : Date.now() + result.expires_in * 1000,
  };
}

const q = query({
  prompt: 'Summarize the current deployment configuration.',
  options: {
    auth: serviceAccount({ fetchServiceAccountToken }),
  },
});
The scope and callback return value are configured as follows:
  • When obtaining the SAT, enter the scopes that it should contain. For example, use models.read chat.completions to list models and call the inference API.
  • Put the SAT returned by Token exchange in the callback result. You can also provide the SAT expiry.
  • When a valid SAT cannot be obtained, return null (None in Python) or throw an exception so the current session fails explicitly.

Reuse the local sign-in

If the workstation is already signed in through qodercli, the SDK can use the same session. This method is suitable for a developer workstation, not stateless CI or production services.
import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';

const q = query({
  prompt: 'Summarize the current workspace.',
  options: {
    auth: qodercliAuth(),
  },
});

Authentication Failure Callback

When the remote side rejects the token, the token expires, or the CLI exits with an authentication error, use onAuthExpired (TypeScript) / on_auth_expired (Python) to trigger a re-login or token-exchange flow. It fires at most once per SDK session.
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env

def show_sign_in_required() -> None:
    print("Authentication has expired. Please sign in again.")

options = QoderAgentOptions(
    auth=access_token_from_env(),
    on_auth_expired=show_sign_in_required,
)
The SDK does not automatically refresh PATs. After obtaining a new token, create a new SDK session with the new auth configuration.

Authentication Errors

Python SDK authentication configuration errors raise exceptions with a code:
  • Missing authentication configuration: AuthNotConfiguredError, with code == "auth_not_configured".
  • Missing PAT environment variable: AuthAccessTokenEnvVarError, with code == "auth_access_token_env_var_not_configured".
  • Missing Service Account Key environment variable: AuthServiceAccountEnvVarError, with code == "auth_service_account_env_var_not_configured".

Best Practices

  • In production and CI, provide credentials through a secret manager; do not put credentials in source code.
  • Do not write PATs, Service Account keys, or SATs to logs, error objects, or debug output.
  • Configure a PAT or Service Account explicitly for automated environments instead of relying on the local qodercli sign-in.
  • For user-facing applications, register the auth-expired callback to turn authentication failures into clear sign-in prompts.
  • After updating or rotating credentials, create a new SDK session; do not reuse a session that has already failed authentication.