The Secrets Extension provides a secure way for agent builders to request sensitive values, such as API keys, directly from the user. Rather than hardcoding credentials or relying on local environment variables that may not exist in a production environment, the Secrets Extension allows your agent to demand specific values. These can be provided by the user before execution (pre-configured) or requested dynamically during the run if the agent hits a blocker. Once a secret is provided, the platform stores it securely so the user isn’t prompted repeatedly in future sessions.
Users can revoke or update the secret at any time through the GUI.
Basic Secrets Implementation
Here’s how to add secrets capabilities to your agent:
# Copyright 2025 © BeeAI a Series of LF Projects, LLC
# SPDX-License-Identifier: Apache-2.0
import os
from typing import Annotated
from a2a.types import Message
from agentstack_sdk.a2a.extensions.auth.secrets import (
SecretDemand,
SecretsExtensionServer,
SecretsExtensionSpec,
SecretsServiceExtensionParams,
)
from agentstack_sdk.server import Server
server = Server()
@server.agent()
async def basic_secrets_example(
input: Message,
secrets: Annotated[
SecretsExtensionServer,
SecretsExtensionSpec.single_demand(key="SLACK_API_KEY", name="Slack", description="Access to Slack"),
],
):
"""Agent that requests a secret that can be provided during runtime"""
if secrets and secrets.data and secrets.data.secret_fulfillments:
yield f"Slack API key: {secrets.data.secret_fulfillments['SLACK_API_KEY'].secret}"
else:
try:
runtime_provided_secrets = await secrets.request_secrets(
params=SecretsServiceExtensionParams(
secret_demands={"SLACK_API_KEY": SecretDemand(description="I really need Slack Key", name="Slack")}
)
)
except ValueError:
runtime_provided_secrets = None
if runtime_provided_secrets and runtime_provided_secrets.secret_fulfillments:
yield f"Slack API key: {runtime_provided_secrets.secret_fulfillments['SLACK_API_KEY'].secret}"
else:
yield "No Slack API key provided"
def run():
server.run(host=os.getenv("HOST", "127.0.0.1"), port=int(os.getenv("PORT", 8000)))
if __name__ == "__main__":
run()
Import the Secrets extension
Import SecretsExtensionServer, SecretsExtensionSpec, SecretDemand, and SecretsServiceExtensionParams from agentstack_sdk.a2a.extensions.auth.secrets.
Add secrets parameter to your agent
Add a secrets parameter to your agent function using the Annotated type hint with SecretsExtensionServer and SecretsExtensionSpec.
Define your secret demands
Create SecretDemand objects for each secret your agent needs, specifying the name and description.
Handle secret fulfillment
Check if secrets are provided and use await secrets.request_secrets(params=...) to request them dynamically if missing. Ensure your agent handles cases where secrets are not provided.
Always check if the secrets extension is available before using it to comply with plain A2A clients.
Usage Patterns
There are two main patterns for working with secrets in your agents:
When secrets are provided before the agent runs, they’re available immediately in the secrets.data.secret_fulfillments object. This is the preferred approach as it provides a smoother user experience.
# Check if secrets are pre-configured
if secrets and secrets.data and secrets.data.secret_fulfillments:
api_key = secrets.data.secret_fulfillments['default'].secret
# Use the secret immediately
Dynamic Secret Requests
When secrets aren’t pre-configured, you can request them during runtime using await secrets.request_secrets(). This is useful when your agent needs to ask for secrets based on user input or when the secret requirement is conditional.
# Request secrets dynamically
runtime_secrets = await secrets.request_secrets(
params=SecretsServiceExtensionParams(
secret_demands={"default": SecretDemand(description="API key needed", name="API Key")}
)
)