Credentials API for Gemini Managed Agents

September 28, 20266 minute read

We recently shipped the Credentials API for Managed Agents (antigravity-preview-09-2026). It lets your agent authenticate with external services like GitHub, Notion, or the Gemini API without putting raw secrets inside the Linux sandbox.

Credentials API end-to-end flow

If you pass an API key as a normal environment variable, any dependency or script inside the sandbox can read os.environ and leak it. With the Credentials API, the secret stays on the server and is injected on the wire by the egress proxy.

How it works

1. Store the secret once

Register a credential with credentials.create(). Secrets are write-only and encrypted at rest; API responses only return metadata (id, type, status, timestamps).

Step 1: Store the secret once

There are 3 credential types:

  • bearer_token: Static tokens and API keys injected as HTTP headers (Authorization: Bearer <token> by default, or custom header_name and prefix).
  • oauth2: Refresh tokens (client_id, client_secret, refresh_token, token_url). Gemini exchanges and refreshes access tokens automatically before expiry.
  • environment_variable: For CLIs and SDKs that read secrets from the process environment. The container receives a placeholder (__GEMINI_CRED_<id>__), and the egress proxy swaps in the real value only for requests to trusted_domains.

2. Reference it by ID

Pass the credential id when defining a reusable agent with agents.create() (or per run in interactions.create()) on a remote mcp_server tool, a domain in network.allowlist, or a variable in base_environment.env.

Step 2: Reference it by ID

3. Injected on the wire

When the agent calls an MCP tool or makes an outbound HTTP request from the sandbox, the egress proxy checks the target domain and injects the real credential on the wire.

Step 3: Injected on the wire

Example Reviewing and smoke-testing GitHub PRs

Here is a practical examples on a reusable custom agent that manages google-gemini/cookbook via the Github MCP server and can make securte Gemini API calls. The GEMINI_API_KEY is bound as a credential, untrusted code in the sandbox can call generativelanguage.googleapis.com without ever seeing the real API key.

Architecture diagram: GitHub MCP bearer_token plus sandbox GEMINI_API_KEY environment_variable

Create a read-only GitHub token

  1. Open GitHub Fine-grained Personal Access Tokens and click Generate new token.
  2. Scope Repository access to your target repositories and set Pull requests and Contents permissions to Read-only.
  3. Export GITHUB_PAT and GEMINI_API_KEY locally.

Run the agent

Install the SDK (bun add @google/genai) and run:

TypeScript
import { GoogleGenAI } from "@google/genai";
 
const ai = new GoogleGenAI({});
 
// 1. Store credentials once
const github = await ai.credentials.create({
  id: "github-mcp",
  type: "bearer_token",
  token: process.env.GITHUB_PAT!,
});
 
const geminiKey = await ai.credentials.create({
  id: "gemini-key",
  type: "environment_variable",
  value: process.env.GEMINI_API_KEY!,
  injection_location: ["header", "query"],
  trusted_domains: ["generativelanguage.googleapis.com"],
});
 
// 2. Define a reusable agent wired to both credentials
const agent = await ai.agents.create({
  id: "cookbook-pr-reviewer",
  base_agent: "antigravity-preview-09-2026",
  system_instruction:
    "You are a maintainer for google-gemini/cookbook. Use the github tools to inspect pull requests, and use the sandbox to smoke-test Gemini API snippets and draft release notes.",
  tools: [
    { type: "code_execution" },
    {
      type: "mcp_server",
      name: "github",
      url: "https://api.githubcopilot.com/mcp/",
      credential: github.id,
    },
  ],
  base_environment: {
    type: "remote",
    env: {
      GEMINI_API_KEY: { credential: geminiKey.id },
    },
  },
});
 
// 3. Run the agent
const interaction = await ai.interactions.create(
  {
    agent: agent.id,
    environment: "remote",
    input:
      "Draft a release note for the 3 most recently merged PRs in google-gemini/cookbook, and run a live smoke test against gemini-3.8-flash in the sandbox to verify the code snippet works.",
  },
  { timeout: 300000 },
);
 
console.log(interaction.output_text);

Output:

Markdown
# Release Notes: `google-gemini/cookbook`
 
### 1. [PR #1347](https://github.com/google-gemini/cookbook/pull/1347) - Zero-Cloud Local Hybrid RAG Recipe with SQLite FTS5 & Gemini
- **Author:** @Cagrik34 | **Merged At:** 2026-09-28 10:49:52 UTC
- **Summary:** Combines SQLite FTS5 (`unicode61`) BM25 search with `text-embedding-004` dense vectors and Reciprocal Rank Fusion (RRF, k=60) in `examples/Zero_Cloud_Hybrid_RAG_SQLite_FTS5_Gemini.ipynb`.
 
### 2. [PR #1383](https://github.com/google-gemini/cookbook/pull/1383) - Fix `musicGenerationConfig` Schema in Lyria RealTime Notebook
- **Author:** @kkorpal | **Merged At:** 2026-09-28 10:29:00 UTC
- **Summary:** Updates `music_generation_config` to `musicGenerationConfig` and flattens the payload in `quickstarts/Get_started_LyriaRealTime.ipynb`.
 
### 3. [PR #1384](https://github.com/google-gemini/cookbook/pull/1384) - Fix HTTP 400 BadRequest via File API in Prompting Notebook
- **Author:** @kkorpal | **Merged At:** 2026-09-25 12:29:48 UTC
- **Summary:** Switches multimodal image upload in `quickstarts/Prompting.ipynb` to `client.files.upload`.

What happens during the run:

  1. GitHub MCP (github-mcp): Connects to api.githubcopilot.com/mcp/ and calls github:list_pull_requests and github:pull_request_read to inspect the latest merged PRs (#1347, #1383, #1384).
  2. Sandbox execution (gemini-key): Inside the container, $GEMINI_API_KEY is __GEMINI_CRED_gemini-key__. When the smoke test calls generativelanguage.googleapis.com, the egress proxy swaps the placeholder for the real key on the wire.
  3. Domain restriction: Any request carrying __GEMINI_CRED_gemini-key__ to a domain outside trusted_domains is blocked (403).

Rotate or delete credentials

Update a credential by ID to rotate its secret without changing your agent definition, or delete it when it is no longer needed:

TypeScript
await ai.credentials.update("github-mcp", {
  type: "bearer_token",
  token: process.env.GITHUB_PAT_NEW!,
});
 
await ai.credentials.delete("github-mcp");
await ai.credentials.delete("gemini-key");

See the Credentials API docs, Custom Agents guide, and Managed Agents Quickstart for full details.

Thanks for reading! If you have any questions or feedback, please let me know on Twitter or LinkedIn.