受管理的代理中的凭据

凭据是服务器管理的密钥,可让您的代理访问第三方服务,而无需将密钥输入到代理的环境中。您只需存储一次凭据,然后通过 ID 引用该凭据,出站代理会在请求时解析并注入该凭据。

Secret 值是只写值。存储后,任何端点都不会返回这些令牌,因此遭到入侵的代理无法读取其正在使用的令牌。

您使用凭据的主要位置是 environment.network 上的网络许可名单。先存储 Secret:

Python

from google import genai

client = genai.Client()

credential = client.credentials.create(
    id="github-production",
    type="bearer_token",
    token="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
)

print(f"Credential ID: {credential.id}, Status: {credential.status}")

JavaScript

import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({});

const credential = await client.credentials.create({
    id: "github-production",
    type: "bearer_token",
    token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
});

console.log(`Credential ID: ${credential.id}, Status: ${credential.status}`);

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/credentials" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "id": "github-production",
    "type": "bearer_token",
    "token": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}'

然后将其附加到它所验证的网域:

Python

interaction = client.interactions.create(
    agent="antigravity-preview-09-2026",
    input="Triage the open issues in my-org/my-repo.",
    environment={
        "type": "remote",
        "network": {
            "allowlist": [
                {"domain": "api.github.com", "credential": "github-production"},
                {"domain": "*"},
            ]
        },
    },
)

JavaScript

const interaction = await client.interactions.create({
    agent: "antigravity-preview-09-2026",
    input: "Triage the open issues in my-org/my-repo.",
    environment: {
        type: "remote",
        network: {
            allowlist: [
                { domain: "api.github.com", credential: "github-production" },
                { domain: "*" },
            ],
        },
    },
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "agent": "antigravity-preview-09-2026",
    "input": "Triage the open issues in my-org/my-repo.",
    "environment": {
        "type": "remote",
        "network": {
            "allowlist": [
                { "domain": "api.github.com", "credential": "github-production" },
                { "domain": "*" }
            ]
        }
    }
}'

现在,代理会向 api.github.com 发出经过身份验证的请求,并且令牌永远不会存在于沙盒中。

凭据类型

每项凭据都有一个 type,用于确定凭据接受哪些字段以及代理如何应用凭据。

类型 使用场景 行为
bearer_token 个人访问令牌、机器人令牌、静态 API 密钥 代理将令牌作为请求标头注入。无刷新逻辑。
oauth2 OAuth 应用和用户委托流程 代理会将刷新令牌交换为访问令牌,并在访问令牌过期时刷新它们。
environment_variable 从进程环境中读取 Secret 的客户端 SDK 代理的环境会收到一个占位符。代理会替换出站请求中的真实密钥。

使用网络许可名单中的凭据

credential 添加到许可名单规则中,代理会验证向该网域发出的每个出站请求。这是向代理授予对私有 API、私有代码库或私有存储桶的访问权限的推荐方法。

您可以在同一许可名单中混用经过身份验证的规则和未经身份验证的规则:

Python

interaction = client.interactions.create(
    agent="antigravity-preview-09-2026",
    input="Sync the open Jira issues into the tracking sheet in my repo.",
    environment={
        "type": "remote",
        "sources": [
            {
                "type": "repository",
                "source": "https://github.com/your-org/backend",
                "target": "/backend-app",
            }
        ],
        "network": {
            "allowlist": [
                {"domain": "github.com", "credential": "github-production"},
                {"domain": "api.atlassian.com", "credential": "jira-oauth"},
                {"domain": "*.googleapis.com"},
            ]
        },
    },
)

JavaScript

const interaction = await client.interactions.create({
    agent: "antigravity-preview-09-2026",
    input: "Sync the open Jira issues into the tracking sheet in my repo.",
    environment: {
        type: "remote",
        sources: [
            {
                type: "repository",
                source: "https://github.com/your-org/backend",
                target: "/backend-app",
            },
        ],
        network: {
            allowlist: [
                { domain: "github.com", credential: "github-production" },
                { domain: "api.atlassian.com", credential: "jira-oauth" },
                { domain: "*.googleapis.com" },
            ],
        },
    },
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "agent": "antigravity-preview-09-2026",
    "input": "Sync the open Jira issues into the tracking sheet in my repo.",
    "environment": {
        "type": "remote",
        "sources": [
            {
                "type": "repository",
                "source": "https://github.com/your-org/backend",
                "target": "/backend-app"
            }
        ],
        "network": {
            "allowlist": [
                { "domain": "github.com", "credential": "github-production" },
                { "domain": "api.atlassian.com", "credential": "jira-oauth" },
                { "domain": "*.googleapis.com" }
            ]
        }
    }
}'

由于代理会针对每个请求解析凭据,因此 oauth2 凭据会以透明方式刷新其访问令牌。当访问令牌过期时,长时间运行的互动不会中断。

合并 credentialtransform

许可名单规则还接受内嵌的 transform 对象,该对象可直接在规则中设置标头。这两种机制均由出口代理在网络上应用,因此在两种情况下,标头值都不会存在于沙盒内。这两个字段可以出现在同一条规则中。

规则配置 行为
credential 代理会解析凭据,并在向网域发出的每个请求中注入其标头。
transform 静态标头注入。您撰写的标头会按原样发送。
两者都有 系统会先应用凭据,然后将 transform 合并到顶部。如果两者设置了相同的键,则显式 transform 标头胜出。
都不是 允许该网域,并且不注入任何标头。

如果您希望存储一次 Secret,然后从项目中的每个环境、代理和触发器引用该 Secret,并且希望系统为您处理访问令牌刷新和轮换,那么凭据就非常有用。如果值属于单个调用,例如在创建互动之前自行生成的令牌,则适合使用内嵌 transform

将两者结合起来是很常见的做法。凭据包含身份验证标头,并添加上游服务在同一请求中所需的任何其他内容:transform

{
    "domain": "api.atlassian.com",
    "credential": "jira-oauth",
    "transform": {
        "X-Atlassian-Workspace": "my-workspace-id"
    }
}

如需将密钥从内嵌 transform 移至凭据,请使用 POST /credentials 存储该密钥,将 transform 中的身份验证标头替换为 "credential": "<id>",然后将 transform 对象的其余部分保持不变。

将凭据与 MCP 服务器搭配使用

远程 MCP 服务器采用相同的 credential 字段。在 mcp_server 工具上设置该标头,然后代理会将身份验证标头注入到发送给该服务器的每个请求中:

Python

interaction = client.interactions.create(
    agent="antigravity-preview-09-2026",
    input="Create a new issue in my-org/my-repo",
    environment="remote",
    tools=[{
        "type": "mcp_server",
        "name": "github",
        "url": "https://api.githubcopilot.com/mcp",
        "credential": "github-production",
    }],
)

JavaScript

const interaction = await client.interactions.create({
    agent: "antigravity-preview-09-2026",
    input: "Create a new issue in my-org/my-repo",
    environment: "remote",
    tools: [{
        type: "mcp_server",
        name: "github",
        url: "https://api.githubcopilot.com/mcp",
        credential: "github-production",
    }],
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "agent": "antigravity-preview-09-2026",
    "input": "Create a new issue in my-org/my-repo",
    "environment": "remote",
    "tools": [
        {
            "type": "mcp_server",
            "name": "github",
            "url": "https://api.githubcopilot.com/mcp",
            "credential": "github-production"
        }
    ]
}'

credentialheaders 遵循与许可名单相同的优先规则。凭据先应用,然后 headers 合并到顶部,因此如果两者都设置了相同的键,则显式标头胜出:

{
    "type": "mcp_server",
    "name": "jira",
    "url": "https://jira.atlassian.com/mcp",
    "credential": "jira-oauth",
    "headers": {
        "X-Atlassian-Workspace": "my-workspace-id"
    }
}

如需将密钥从内嵌 headers 移至凭据,请使用 POST /credentials 存储该密钥,并将 headers 中的身份验证条目替换为 credential。将其他标题保留在原位。

将凭据用作环境变量

某些客户端库从进程环境中读取密钥,而不是将其作为请求标头接受。套接字模式和长轮询客户端是常见情况。

environment_variable 凭据绑定到 environment.env 下的变量名称:

Python

interaction = client.interactions.create(
    agent="antigravity-preview-09-2026",
    input="Run the sync script and check notifications.",
    environment={
        "type": "remote",
        "env": {
            "NODE_ENV": "production",
            "SLACK_BOT_TOKEN": {"credential": "slack-bot-token"},
        },
    },
)

JavaScript

const interaction = await client.interactions.create({
    agent: "antigravity-preview-09-2026",
    input: "Run the sync script and check notifications.",
    environment: {
        type: "remote",
        env: {
            NODE_ENV: "production",
            SLACK_BOT_TOKEN: { credential: "slack-bot-token" },
        },
    },
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "agent": "antigravity-preview-09-2026",
    "input": "Run the sync script and check notifications.",
    "environment": {
        "type": "remote",
        "env": {
            "NODE_ENV": "production",
            "SLACK_BOT_TOKEN": { "credential": "slack-bot-token" }
        }
    }
}'

env 接受字面值字符串和凭据引用。一个字面量字符串作为普通明文变量注入到容器中。

凭据引用不是。该变量接收占位符 __GEMINI_CRED_<credential-id>__,并且代理仅针对发送到凭据 trusted_domains 中网域的出站请求换入真实 Secret。对任何其他网域的请求都会被拒绝,因此密钥永远不会离开安全边界,也不会发送占位符来代替密钥。

为每个 environment_variable 凭据设置 trusted_domains。它是一种控制机制,用于限定密文的使用范围。

创建凭据

每个创建请求都需要一个 type,以及相应类型所需的任何字段。

直接调用 REST 时,所有字段名称都使用 snake_case。发送 camelCase 字段会返回 400

不记名令牌

不记名令牌凭据只需 token

Python

credential = client.credentials.create(
    id="github-production",
    type="bearer_token",
    token="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
)

JavaScript

const credential = await client.credentials.create({
    id: "github-production",
    type: "bearer_token",
    token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/credentials" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "id": "github-production",
    "type": "bearer_token",
    "token": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}'

响应仅返回元数据,绝不会返回令牌:

{
  "id": "github-production",
  "type": "bearer_token",
  "status": "active",
  "create_time": "2026-07-15T10:00:00.000000000Z",
  "update_time": "2026-07-15T10:00:00.000000000Z"
}

默认情况下,代理会发送 Authorization: Bearer <token>。替换 header_nameprefix 以定位到需要其他内容的相应服务:

Python

credential = client.credentials.create(
    id="my-api-key",
    type="bearer_token",
    token="key_xxxxxxxxxxxx",
    header_name="x-goog-api-key",
    prefix="",
)

JavaScript

const credential = await client.credentials.create({
    id: "my-api-key",
    type: "bearer_token",
    token: "key_xxxxxxxxxxxx",
    header_name: "x-goog-api-key",
    prefix: "",
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/credentials" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "id": "my-api-key",
    "type": "bearer_token",
    "token": "key_xxxxxxxxxxxx",
    "header_name": "x-goog-api-key",
    "prefix": ""
}'

此配置会生成标头 x-goog-api-key: key_xxxxxxxxxxxx

下表显示了 header_nameprefix 的组合方式:

配置 注入的标头
{"token": "ghp_xxx"} Authorization: Bearer ghp_xxx
{"token": "sk_live_xxx"} Authorization: Bearer sk_live_xxx
{"token": "key_xxx", "header_name": "x-goog-api-key", "prefix": ""} x-goog-api-key: key_xxx
{"token": "mytoken", "header_name": "X-API-Token", "prefix": ""} X-API-Token: mytoken

OAuth2

OAuth2 凭据需要 client_idclient_secretrefresh_tokentoken_urlscopes 字段为可选字段:

Python

credential = client.credentials.create(
    id="jira-oauth",
    type="oauth2",
    client_id="my-client-id",
    client_secret="my-client-secret",
    token_url="https://auth.atlassian.com/oauth/token",
    refresh_token="rt_xxxxxxxxxxxxxxxxxxxx",
    scopes=["read:jira-work", "write:jira-work"],
)

JavaScript

const credential = await client.credentials.create({
    id: "jira-oauth",
    type: "oauth2",
    client_id: "my-client-id",
    client_secret: "my-client-secret",
    token_url: "https://auth.atlassian.com/oauth/token",
    refresh_token: "rt_xxxxxxxxxxxxxxxxxxxx",
    scopes: ["read:jira-work", "write:jira-work"],
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/credentials" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "id": "jira-oauth",
    "type": "oauth2",
    "client_id": "my-client-id",
    "client_secret": "my-client-secret",
    "token_url": "https://auth.atlassian.com/oauth/token",
    "refresh_token": "rt_xxxxxxxxxxxxxxxxxxxx",
    "scopes": ["read:jira-work", "write:jira-work"]
}'

创建 OAuth2 凭据时,系统会针对 token_url 执行实时令牌交换,以确认配置有效。仅当提供方返回包含 access_token 的成功令牌响应时,系统才会存储凭据。系统接受 JSON 和 form-urlencoded 响应。

这意味着您需要在创建时提供有效且未过期的刷新令牌。如果提供方拒绝交换,系统会向您返回错误:

{
  "error": {
    "message": "OAuth token validation failed with HTTP 403: {\"error\":\"unauthorized_client\",\"error_description\":\"refresh_token is invalid\"}",
    "code": "invalid_request"
  }
}

存储后,代理会在访问令牌过期时刷新它们。如果提供方轮替刷新令牌并在刷新期间返回新的刷新令牌,则新令牌会自动替换存储的令牌。

环境变量

environment_variable 凭据需要 valueinjection_location

Python

credential = client.credentials.create(
    id="slack-bot-token",
    type="environment_variable",
    value="xoxb-xxxxxxxxxxxx-xxxxxxxxxxxx",
    trusted_domains=["*.slack.com", "slack.com"],
    injection_location="header",
)

JavaScript

const credential = await client.credentials.create({
    id: "slack-bot-token",
    type: "environment_variable",
    value: "xoxb-xxxxxxxxxxxx-xxxxxxxxxxxx",
    trusted_domains: ["*.slack.com", "slack.com"],
    injection_location: "header",
});

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/credentials" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "id": "slack-bot-token",
    "type": "environment_variable",
    "value": "xoxb-xxxxxxxxxxxx-xxxxxxxxxxxx",
    "trusted_domains": ["*.slack.com", "slack.com"],
    "injection_location": "header"
}'

injection_location 字段用于告知代理在出站请求中替换 Secret 的位置。它接受 headerquerybody,可以作为单个字符串,也可以作为数组(当服务需要多个时):

"injection_location": ["header", "query"]

替换仅在您列出的位置进行。如果请求在其他任何位置携带占位符,则会被拒绝,而不是继续发送。

如需将凭据绑定到变量名称,请参阅将凭据用作环境变量

生成的 ID

id 字段为可选字段。如果省略此参数,服务会生成一个 UUID:

{
  "id": "9e545973-4330-49bb-9a44-930cea9fbe3c",
  "type": "bearer_token",
  "status": "active",
  "create_time": "2026-07-15T10:00:00.000000000Z",
  "update_time": "2026-07-15T10:00:00.000000000Z"
}

如果您希望使用稳定且易读的引用来处理各种互动,请提供您自己的 ID。由于 ID 会显示在资源路径中,因此最好使用带连字符或下划线的小写字母数字字符。

列出凭据

列出属于项目的凭据。使用分页参数控制响应批次大小。

Python

response = client.credentials.list(page_size=10)
for credential in response.credentials:
    print(f"Credential ID: {credential.id}, Type: {credential.type}")

JavaScript

const response = await client.credentials.list({ page_size: 10 });
for (const credential of response.credentials) {
    console.log(`Credential ID: ${credential.id}, Type: ${credential.type}`);
}

REST

curl -X GET "https://generativelanguage.googleapis.com/v1beta/credentials?page_size=10" \
-H "x-goog-api-key: $GEMINI_API_KEY"

响应仅包含元数据:

{
  "credentials": [
    {
      "id": "github-production",
      "type": "bearer_token",
      "status": "active",
      "create_time": "2026-07-15T10:00:00.000000000Z",
      "update_time": "2026-07-15T10:00:00.000000000Z"
    },
    {
      "id": "jira-oauth",
      "type": "oauth2",
      "status": "active",
      "create_time": "2026-07-15T10:05:00.000000000Z",
      "update_time": "2026-07-15T10:05:00.000000000Z"
    }
  ],
  "next_page_token": "Cj...5aE="
}

next_page_token 作为 page_token 传回,以获取下一页。如果没有更多结果,则省略此字段。

参数 类型 说明
page_size integer 每个页面的凭据数量上限。
page_token 字符串 上一个响应的 next_page_token 中的令牌。

获取凭据

按 ID 检索特定凭据的元数据。

Python

credential = client.credentials.get(id="github-production")
print(f"Credential ID: {credential.id}, Status: {credential.status}")

JavaScript

const credential = await client.credentials.get("github-production");
console.log(`Credential ID: ${credential.id}, Status: ${credential.status}`);

REST

curl -X GET "https://generativelanguage.googleapis.com/v1beta/credentials/github-production" \
-H "x-goog-api-key: $GEMINI_API_KEY"

响应类似于以下内容:

{
  "id": "github-production",
  "type": "bearer_token",
  "status": "active",
  "create_time": "2026-07-15T10:00:00.000000000Z",
  "update_time": "2026-08-01T14:30:00.000000000Z"
}

请求不存在的凭据会返回 404

{
  "error": {
    "message": "Result not found.; GetCredential call failed",
    "code": "not_found"
  }
}

轮替凭据

替换某个 Secret,而不影响引用该 Secret 的任何许可名单规则、工具定义或环境变量。旋转会在下个代理分辨率生效。

请求必须包含 type 以及您要更改的字段。您省略的字段将保留其当前值。

轮替不记名令牌:

Python

credential = client.credentials.update(
    id="github-production",
    type="bearer_token",
    token="ghp_new_xxxxxxxxxxxxxxxxxxxx",
)

JavaScript

const credential = await client.credentials.update("github-production", {
    type: "bearer_token",
    token: "ghp_new_xxxxxxxxxxxxxxxxxxxx",
});

REST

curl -X PATCH "https://generativelanguage.googleapis.com/v1beta/credentials/github-production" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "type": "bearer_token",
    "token": "ghp_new_xxxxxxxxxxxxxxxxxxxx"
}'

轮换 OAuth2 刷新令牌:

Python

credential = client.credentials.update(
    id="jira-oauth",
    type="oauth2",
    refresh_token="rt_new_xxxxxxxxxxxxxxxxxxxx",
)

JavaScript

const credential = await client.credentials.update("jira-oauth", {
    type: "oauth2",
    refresh_token: "rt_new_xxxxxxxxxxxxxxxxxxxx",
});

REST

curl -X PATCH "https://generativelanguage.googleapis.com/v1beta/credentials/jira-oauth" \
-H "Content-Type: application/json" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-d '{
    "type": "oauth2",
    "refresh_token": "rt_new_xxxxxxxxxxxxxxxxxxxx"
}'

响应反映了新的 update_time

{
  "id": "jira-oauth",
  "type": "oauth2",
  "status": "active",
  "create_time": "2026-07-15T10:05:00.000000000Z",
  "update_time": "2026-08-01T14:30:00.000000000Z"
}

凭据的 type 在创建时即已确定。如需更改,请删除相应凭据并创建新凭据。

删除凭据

在不再需要凭据及其存储的密钥时,将其删除。

Python

client.credentials.delete(id="github-production")

JavaScript

await client.credentials.delete("github-production");

REST

curl -X DELETE "https://generativelanguage.googleapis.com/v1beta/credentials/github-production" \
-H "x-goog-api-key: $GEMINI_API_KEY"

成功删除后会返回一个空对象:

{}

任何仍引用该 ID 的许可名单规则、工具或环境变量都将无法解析,因此请先更新这些内容。

字段参考

每种凭据通用的字段:

字段 类型 是否必需 说明
id string 唯一标识符。如果省略,则以 UUID 形式生成。
type 字符串 bearer_tokenoauth2environment_variable 之一。
status 字符串 只读 凭据的当前状态。
create_time 字符串 只读 RFC 3339 创建时间戳。
update_time 字符串 只读 上次更新的 RFC 3339 时间戳。

bearer_token 的字段:

字段 类型 是否必需 说明
token 字符串 只写。令牌值。
header_name 字符串 要注入的标头。默认为 Authorization
prefix 字符串 值前缀。默认为 Bearer。如果设为 "",则表示没有。

oauth2 的字段:

字段 类型 是否必需 说明
client_id 字符串 OAuth2 客户端 ID。
client_secret 字符串 只写。OAuth2 客户端密钥。
refresh_token 字符串 只写。用于获取访问令牌的刷新令牌。
token_url 字符串 提供方令牌端点。
scopes 数组 要请求的 OAuth 范围。

environment_variable 的字段:

字段 类型 是否必需 说明
value 字符串 只写。相应 Secret 的值。
injection_location 字符串或数组 要替换 Secret 的位置。headerquerybody 中的一个或多个。
trusted_domains 数组 授权用于替换的网域模式。

错误

如果出现错误,系统会返回一个包含 messagecode 的 JSON 对象:

{
  "error": {
    "message": "Credential 'github-production' already exists.; CreateCredential call failed",
    "code": "aborted"
  }
}
HTTP 状态 code 原因
400 invalid_request 缺少必填字段、存在未知字段、type 不受支持或 OAuth2 验证失败。
404 not_found 没有具有该 ID 的凭据。
409 aborted 已存在使用该 ID 的凭据。

系统会拒绝未知字段,而不是忽略它们,并且错误会指明相应字段:

{
  "error": {
    "message": "Unknown parameter 'headerName'. Did you mean 'header_name'?",
    "code": "invalid_request"
  }
}

后续步骤

  • 环境:了解智能体如何运行代码和持久保存文件。
  • 代理概览:了解受管代理的核心概念。
  • 构建自定义代理:使用 AGENTS.mdSKILL.md 定义您自己的代理。