Учетные данные в управляемых агентах

Учетные данные – это секреты, управляемые сервером, которые позволяют агентам получать доступ к сторонним сервисам, не вводя секрет в среду агента. Вы сохраняете учетные данные один раз, ссылаетесь на них по идентификатору, а исходящий прокси-сервер разрешает и вставляет их во время запроса.

Значения секретов доступны только для записи. После сохранения они никогда не возвращаются ни одной конечной точкой, поэтому взломанный агент не может прочитать используемые им токены.

Основное место, где используются учетные данные, – это белый список сети на странице environment.network. Сначала сохраните секрет:

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}`);

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Create(ctx, operations.CreateCredentialRequest{
        Body: credentials.NewCredentialCreateParams(credentials.HTTPBearerConfig{
            ID:    "github-production",
            Token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Credential ID: %s, Status: %v\n", res.Credential.ID, res.Credential.GetStatus())
}

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: "*" },
            ],
        },
    },
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateAgentInteraction{
            Agent: interactions.AgentOption("antigravity-preview-09-2026"),
            Input: interactions.NewInteractionsInput("Triage the open issues in my-org/my-repo."),
            Environment: genai.Ptr(interactions.NewCreateAgentInteractionEnvironment(interactions.Environment{
                Network: genai.Ptr(interactions.NewNetwork(interactions.EnvironmentNetworkEgressAllowlist{
                    Allowlist: genai.Ptr(interactions.NewAllowlist([]interactions.AllowlistEntry{
                        {Domain: "api.github.com", Credential: genai.Ptr("github-production")},
                        {Domain: "*"},
                    })),
                })),
            })),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res.Interaction.GetOutputText())
}

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 Клиентские 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" },
            ],
        },
    },
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateAgentInteraction{
            Agent: interactions.AgentOption("antigravity-preview-09-2026"),
            Input: interactions.NewInteractionsInput("Sync the open Jira issues into the tracking sheet in my repo."),
            Environment: genai.Ptr(interactions.NewCreateAgentInteractionEnvironment(interactions.Environment{
                Sources: []interactions.Source{
                    {
                        Type:   interactions.SourceTypeRepository.ToPointer(),
                        Source: genai.Ptr("https://github.com/your-org/backend"),
                        Target: genai.Ptr("/backend-app"),
                    },
                },
                Network: genai.Ptr(interactions.NewNetwork(interactions.EnvironmentNetworkEgressAllowlist{
                    Allowlist: genai.Ptr(interactions.NewAllowlist([]interactions.AllowlistEntry{
                        {Domain: "github.com", Credential: genai.Ptr("github-production")},
                        {Domain: "api.atlassian.com", Credential: genai.Ptr("jira-oauth")},
                        {Domain: "*.googleapis.com"},
                    })),
                })),
            })),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res.Interaction.GetOutputText())
}

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 прозрачно обновляют токен доступа. Долго выполняемое взаимодействие не прерывается, когда срок действия токена доступа истекает.

Сочетание эмодзи credential и transform

Правила белого списка также принимают встроенный объект transform, который задает заголовки непосредственно в правиле. Оба механизма применяются исходящим прокси-сервером, поэтому в обоих случаях значение заголовка никогда не существует в песочнице. Оба поля могут быть указаны в одном правиле.

Конфигурация правила Поведение
Только credential Прокси-сервер разрешает учетные данные и вставляет их заголовок в каждый запрос к домену.
Только transform Внедрение статических заголовков. Заголовки отправляются без изменений.
Оба варианта Сначала применяется учетная запись, а затем transform объединяется поверх нее. Если оба заголовка задают один и тот же ключ, приоритет имеет явный заголовок transform.
Ни то ни другое Домен разрешен, и заголовки не добавляются.

Учетные данные стоит использовать, если вы хотите сохранить секрет один раз и ссылаться на него из каждой среды, агента и триггера в своем проекте, а также если вы хотите, чтобы обновление и ротация токенов доступа выполнялись автоматически. Встроенный 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",
    }],
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateAgentInteraction{
            Agent: interactions.AgentOption("antigravity-preview-09-2026"),
            Input: interactions.NewInteractionsInput("Create a new issue in my-org/my-repo"),
            Environment: genai.Ptr(interactions.NewCreateAgentInteractionEnvironment(interactions.Environment{
                Network: genai.Ptr(interactions.NewNetwork(interactions.EnvironmentNetworkEgressAllowlist{
                    Allowlist: genai.Ptr(interactions.NewAllowlist([]interactions.AllowlistEntry{
                        {Domain: "api.githubcopilot.com", Credential: genai.Ptr("github-production")},
                    })),
                })),
            })),
            Tools: []interactions.Tool{
                interactions.NewTool(interactions.MCPServer{
                    Name: genai.Ptr("github"),
                    URL:  genai.Ptr("https://api.githubcopilot.com/mcp"),
                }),
            },
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res.Interaction.GetOutputText())
}

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"
        }
    ]
}'

Правила credential и headers имеют тот же приоритет, что и белый список. Сначала применяется учетные данные, а затем 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" },
        },
    },
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateAgentInteraction{
            Agent: interactions.AgentOption("antigravity-preview-09-2026"),
            Input: interactions.NewInteractionsInput("Run the sync script and check notifications."),
            Environment: genai.Ptr(interactions.NewCreateAgentInteractionEnvironment(interactions.Environment{
                Env: genai.Ptr(interactions.NewEnv(map[string]interactions.EnvVar{
                    "NODE_ENV":        {Value: genai.Ptr("production")},
                    "SLACK_BOT_TOKEN": {Credential: genai.Ptr("slack-bot-token")},
                })),
            })),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(res.Interaction.GetOutputText())
}

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 учетных данных. Запрос к любому другому домену отклоняется, поэтому секрет никогда не покидает периметр, а вместо него не отправляется плейсхолдер.

Установите значение trusted_domains для каждого объекта учетных данных environment_variable. Это элемент управления, который определяет, где можно использовать секрет.

Как создать учетные данные

Каждый запрос на создание должен содержать 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",
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Create(ctx, operations.CreateCredentialRequest{
        Body: credentials.NewCredentialCreateParams(credentials.HTTPBearerConfig{
            ID:    "github-production",
            Token: "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created credential: %s\n", res.Credential.ID)
}

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_name и prefix, чтобы указать сервис, который ожидает другие значения:

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: "",
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Create(ctx, operations.CreateCredentialRequest{
        Body: credentials.NewCredentialCreateParams(credentials.HTTPBearerConfig{
            ID:         "my-api-key",
            Token:      "key_xxxxxxxxxxxx",
            HeaderName: genai.Ptr("x-goog-api-key"),
            Prefix:     genai.Ptr(""),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created credential: %s\n", res.Credential.ID)
}

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_name и prefix.

Конфигурация Вставленный заголовок
{"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_id, client_secret, refresh_token и token_url. Поле scopes необязательное:

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"],
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Create(ctx, operations.CreateCredentialRequest{
        Body: credentials.NewCredentialCreateParams(credentials.OAuth2Config{
            ID:           "jira-oauth",
            ClientID:     "my-client-id",
            ClientSecret: "my-client-secret",
            TokenURL:     "https://auth.atlassian.com/oauth/token",
            RefreshToken: "rt_xxxxxxxxxxxxxxxxxxxx",
            Scopes:       []string{"read:jira-work", "write:jira-work"},
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created OAuth2 credential: %s\n", res.Credential.ID)
}

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 требуются value и injection_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",
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Create(ctx, operations.CreateCredentialRequest{
        Body: credentials.NewCredentialCreateParams(credentials.EnvironmentVariableConfig{
            ID:                "slack-bot-token",
            Value:             "xoxb-xxxxxxxxxxxx-xxxxxxxxxxxx",
            TrustedDomains:    []string{"*.slack.com", "slack.com"},
            InjectionLocation: credentials.NewEnvironmentVariableConfigInjectionLocation(credentials.InjectionLocationEnumHeader),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Created environment variable credential: %s\n", res.Credential.ID)
}

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 указывает прокси-серверу, в каком месте исходящего запроса нужно подставить секрет. Он принимает значения header, query или body в виде одной строки или массива, если сервису требуется несколько значений:

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

Замена происходит только в указанных вами местоположениях. Запрос, в котором плейсхолдер находится в другом месте, отклоняется, а не пересылается.

Чтобы привязать учетные данные к названию переменной, ознакомьтесь с разделом Как использовать учетные данные в качестве переменных среды.

Сгенерированные идентификаторы

Поле 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"
}

Укажите собственный идентификатор, если вам нужна стабильная и понятная ссылка для использования в разных взаимодействиях. Поскольку идентификатор появляется в пути к ресурсу, рекомендуется использовать строчные буквы, цифры, дефисы и символы подчеркивания.

Как посмотреть учетные данные

Перечислите учетные данные, относящиеся к вашему проекту. Используйте параметры разбивки на страницы, чтобы контролировать размер пакета ответов.

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}`);
}

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.List(ctx, operations.ListCredentialsRequest{
        PageSize: genai.Ptr(10),
    })
    if err != nil {
        log.Fatal(err)
    }

    for _, cred := range res.CredentialListResponse.Credentials {
        fmt.Printf("Credential ID: %s, Type: %v\n", cred.ID, cred.GetType())
    }
}

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 Целое число Максимальное количество учетных данных на странице.
page_token string Токен из свойства next_page_token предыдущего ответа.

Как получить учетные данные

Получение метаданных для определенных учетных данных по их идентификатору.

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}`);

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Get(ctx, operations.GetCredentialRequest{
        ID: "github-production",
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Credential ID: %s, Status: %v\n", res.Credential.ID, res.Credential.GetStatus())
}

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"
  }
}

Как выполнить ротацию учетных данных

Заменить секрет, не затрагивая ни одно правило белого списка, определение инструмента или переменную среды, которые на него ссылаются. Поворот вступит в силу при следующем разрешении прокси.

Запрос должен содержать элемент 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",
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Update(ctx, operations.UpdateCredentialRequest{
        ID: "github-production",
        Body: credentials.NewCredentialUpdate(credentials.HTTPBearerUpdateConfig{
            Token: genai.Ptr("ghp_new_xxxxxxxxxxxxxxxxxxxx"),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Updated credential %s at %v\n", res.Credential.ID, res.Credential.GetUpdateTime())
}

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",
});

Проложить маршрут

package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/credentials"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    res, err := client.Credentials.Update(ctx, operations.UpdateCredentialRequest{
        ID: "jira-oauth",
        Body: credentials.NewCredentialUpdate(credentials.OAuth2UpdateConfig{
            RefreshToken: genai.Ptr("rt_new_xxxxxxxxxxxxxxxxxxxx"),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Updated credential %s at %v\n", res.Credential.ID, res.Credential.GetUpdateTime())
}

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");

Проложить маршрут

package main

import (
    "context"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    _, err = client.Credentials.Delete(ctx, operations.DeleteCredentialRequest{
        ID: "github-production",
    })
    if err != nil {
        log.Fatal(err)
    }
}

REST

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

При успешном удалении возвращается пустой объект:

{}

Любое правило белого списка, инструмент или переменная среды, в которых по-прежнему используется идентификатор, не будут работать, поэтому сначала обновите их.

Справочник по полям

Поля, общие для всех учетных данных:

Поле Тип Обязательно Описание
id string Нет Уникальный идентификатор. Если не указан, генерируется как UUID.
type string Да bearer_token, oauth2, environment_variable.
status string Только чтение Текущий статус учетных данных.
create_time string Только чтение Временная метка создания в формате RFC 3339.
update_time string Только чтение Временная метка последнего обновления в формате RFC 3339.

Поля для bearer_token:

Поле Тип Обязательно Описание
token string Да Только для записи. Значение токена.
header_name string Нет Заголовок, который нужно внедрить. Значение по умолчанию – Authorization.
prefix string Нет Префикс значения. Значение по умолчанию – Bearer. Если вы не хотите использовать фильтр, укажите значение "".

Поля для oauth2:

Поле Тип Обязательно Описание
client_id string Да Идентификатор клиента OAuth2.
client_secret string Да Только для записи. Секретный код клиента OAuth2.
refresh_token string Да Только для записи. Токен обновления, используемый для получения токенов доступа.
token_url string Да Конечная точка токена поставщика.
scopes Массив Нет Области действия OAuth, которые нужно запросить.

Поля для environment_variable:

Поле Тип Обязательно Описание
value string Да Только для записи. Значение секрета.
injection_location Строка или массив Да Где заменить секрет. Один или несколько из следующих вариантов: header, query, body.
trusted_domains Массив Нет Шаблоны доменов, для которых разрешена подстановка.

Ошибки

В случае ошибки возвращается объект JSON со свойствами message и code:

{
  "error": {
    "message": "Credential 'github-production' already exists.; CreateCredential call failed",
    "code": "aborted"
  }
}
Статус HTTP code Причина
400 invalid_request Отсутствует обязательное поле, неизвестное поле, неподдерживаемый символ type или не пройдена проверка OAuth2.
404 not_found Учетных данных с таким идентификатором нет.
409 aborted Учетные данные с таким идентификатором уже существуют.

Неизвестные поля не игнорируются, а отклоняются. В сообщении об ошибке указывается название поля:

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

Дальнейшие действия