Skip to main content
快速开始

SDK 认证

每个 SDK 会话(TypeScript 的 query()、Python 的 query() / QoderSDKClient)都必须配置一种认证方式。同一个会话只能选择一种:
认证方式代表的身份适用场景
Personal Access Token(PAT)Qoder 用户需要使用该用户权限和数据的脚本、CI 或宿主应用
Service Account组织工作负载不应依赖个人账号的后端服务、CI 和定时任务
本机 qoderclicn 登录态当前登录用户已登录 Qoder 的开发者工作站

使用 PAT

PAT 代表一个 Qoder 用户,适合必须访问该用户权限和数据的自动化。

获取 PAT

Qoder Account Integrations 创建 PAT:
  1. 登录 Qoder。
  2. 打开 Account → Integrations
  3. 选择有效期和所需权限并创建 PAT。
  4. 立即复制生成的值;页面关闭后无法再次查看。
建议为本地脚本、CI 和生产环境分别创建 PAT,以便单独轮换或吊销。

从环境变量读取 PAT

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

const q = query({
  prompt: 'Summarize the current workspace.',
  options: {
    auth: accessTokenFromEnv(),
  },
});
该函数默认读取 QODERCN_PERSONAL_ACCESS_TOKEN。自定义变量名时使用:
auth: accessTokenFromEnv('MY_QODERCN_PAT')
如果 options.env 和进程环境中存在同名变量,SDK 优先读取 options.env 中的值。

直接传入 PAT

可信服务端已经取得 PAT 时,可以直接传入:
import { accessToken, query } from '@qodercn-ai/qodercn-agent-sdk';

const token = await readTokenFromSecretManager();
const q = query({
  prompt: 'List the most recently modified files.',
  options: {
    auth: accessToken(token),
  },
});
SDK 不会自动刷新 PAT。PAT 失效后,应取得新 PAT 并创建新的 SDK 会话。

使用 Service Account

开始前,请让 Qoder 组织管理员创建 Service Account、授予应用所需权限并生成 Key。Key 应保存在密钥管理服务中,并只交给可信的服务端进程或 CI 任务。

直接传入 Service Account Key

当可信服务端已经从密钥管理服务读取 Key 时,可以直接传入:
import { query, serviceAccount } from '@qodercn-ai/qodercn-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(),
  },
});
调用方通过 serviceAccount({ serviceAccountKey })(TypeScript)/ service_account(service_account_key=...)(Python)将 Key 传入本次会话。SDK 和 qoderclicn 会为会话取得并刷新短期 Service Account Token(SAT)。
密钥管理服务
     |
     | Service Account Key
     v
调用方读取 Key
     |
     | serviceAccount({ serviceAccountKey })
     v
SDK 启动 qoderclicn 并获取短期 SAT
     |
     `----> 使用 SAT 认证会话请求
SDK 将 Key 和 SAT 用于当前会话。每次创建新会话时,调用方重新传入 Key。请从密钥管理服务读取 Key,并避免把 Key 字面量写入源码、浏览器包、移动应用、日志或测试快照。

宿主提供并刷新 SAT

如果由集成 SDK 的宿主应用负责换取 SAT,请使用 fetch 回调形式(TypeScript 的 serviceAccount({ fetchServiceAccountToken })、Python 的 service_account(fetch_service_account_token=...))。Service Account Key 保留在宿主进程中,qoderclicn 从宿主回调接收 SAT。 该回调由宿主实现。qoderclicn 需要 SAT 时调用该回调;宿主每次收到请求,都调用 Token exchange 接口并把响应中的新 SAT 返回给 qoderclicn。
qoderclicn
     |
     | 请求 SAT
     v
SDK 宿主中的 fetchServiceAccountToken 回调
     |
     | 使用宿主保管的 Service Account Key 调用 Token exchange
     v
Qoder Token exchange
     |
     `----> 回调把短期 SAT 返回给 qoderclicn
下面的示例展示了完整的宿主刷新逻辑:
import {
  query,
  serviceAccount,
  type ServiceAccountTokenResult,
} from '@qodercn-ai/qodercn-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 }),
  },
});
scope 和回调返回值的含义如下:
  • 换取 SAT 时,填写希望 SAT 包含的 scope。例如,需要获取模型列表并调用推理接口时,可以填写 models.read chat.completions
  • 将 Token exchange 返回的 SAT 放入回调结果;也可以同时提供 SAT 的过期时间。
  • 无法取得有效 SAT 时返回 null(Python 中为 None)或抛出异常,让当前会话明确失败。

复用本机登录态

本机已经通过 qoderclicn 登录时,可以让 SDK 使用同一登录态。该方式适合开发者工作站,不适合无状态 CI 或生产服务。
import { qodercliAuth, query } from '@qodercn-ai/qodercn-agent-sdk';

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

认证失败回调

远端拒绝 token、token 过期或 CLI 以认证错误退出时,可以使用 onAuthExpired(TypeScript)/ on_auth_expired(Python)触发重新登录或换 token 流程。每个 SDK 会话最多触发一次。
from qodercn_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,
)
SDK 不会自动刷新 PAT。拿到新 token 后应创建新的会话并传入新的 auth 配置。

错误

Python SDK 认证配置错误会抛出带 code 的异常:
  • 缺少认证配置:AuthNotConfiguredErrorcode == "auth_not_configured"
  • PAT 环境变量未设置:AuthAccessTokenEnvVarErrorcode == "auth_access_token_env_var_not_configured"
  • Service Account Key 环境变量未设置:AuthServiceAccountEnvVarErrorcode == "auth_service_account_env_var_not_configured"

最佳实践

  • 生产和 CI 中通过密钥管理服务提供凭证,不要在源码中写入凭证。
  • 不要把 PAT、Service Account Key 或 SAT 写入日志、错误对象或调试输出。
  • 自动化环境显式配置 PAT 或 Service Account,不要依赖本机 qoderclicn 登录态。
  • 对用户可见应用注册认证失败回调,把认证失败转成明确的登录提示。
  • 更新或轮换凭证后创建新的 SDK 会话,不要复用已经认证失败的会话。