Dify · LLM apps · API key security
Dify agent API key security: scoping and capping tool calls
Dify's visual workflow builder makes it straightforward to give an LLM app access to external APIs — you configure a tool, enter the API key, and the model can call it. What Dify doesn't give you is a spending boundary for that tool call: no per-run dollar cap, no per-conversation revoke, and no structured log of what the tool actually sent and received. This page covers those gaps and the proxy pattern that fills them.
TL;DR
Dify stores API keys in its credential vault and passes them to tool nodes in your workflow. That's the right architecture for key storage, but the credential is still a raw long-lived key with no spending guardrails. A vault key proxy intercepts tool calls before they reach the vendor: your Dify HTTP tool node calls proxy.keybrake.com/stripe/v1 with a scoped vault key, the proxy enforces a daily dollar cap and an endpoint allowlist, and logs every call with the workflow run ID. Revoking a vault key is one API call; your Dify credential stays untouched.
How Dify tools use API keys
In Dify, external API calls happen through tool nodes — either built-in tools (like the HTTP Request node) or custom API tools you define via an OpenAPI/Swagger schema. When you configure a custom API tool, Dify stores the API key in its encrypted credential vault and injects it into the Authorization header on each call.
The key lifecycle in Dify is: configure once, use across all workflows and all conversation sessions. There's no concept of "this workflow run gets a restricted version of the key." The same Stripe secret key is used whether the agent is processing a $10 charge or a $10,000 one.
Where the credential model breaks down for autonomous agents
For deterministic, human-triggered workflows (a button click that fires one Stripe charge), the shared credential model is fine. The human made a deliberate choice and the action has bounded scope.
The risk surface changes when the LLM is making tool call decisions autonomously — particularly in Dify's Agent mode or in multi-step Chatflow pipelines where the model has latitude to call tools multiple times in a conversation.
| Scenario | Risk with raw API key |
|---|---|
| LLM reasoning loop calls Stripe charge tool twice | Two charges created; no idempotency enforcement at the Dify layer |
| User manipulates the chat to trigger extra charges | Prompt injection can cause the LLM to call the charge tool with a large amount_cents |
| Background agent workflow runs unattended overnight | A stuck loop accumulates charges until you notice; no runtime cap |
| Multi-user Dify deployment sharing one credential | One user's session exhausting a shared spending budget affects all other users |
Configuring a Dify HTTP tool node to use the proxy
The simplest integration is through Dify's HTTP Request node or a custom API tool that points at the Keybrake proxy endpoint:
# In your Dify custom API tool definition (OpenAPI schema excerpt):
servers:
- url: https://proxy.keybrake.com/stripe/v1
components:
securitySchemes:
VaultKey:
type: http
scheme: bearer
description: Keybrake vault key (vault_key_xxx)
security:
- VaultKey: []
You store the vault key in Dify's credential vault (in place of or alongside the real Stripe key), and the proxy handles the forwarding. For an HTTP Request node, the configuration is:
URL: https://proxy.keybrake.com/stripe/v1/payment_intents
Method: POST
Headers:
Authorization: Bearer {{credentials.vault_key}}
Content-Type: application/x-www-form-urlencoded
Body:
amount={{inputs.amount_cents}}
currency=usd
customer={{inputs.customer_id}}
The vault key policy you set in Keybrake:
{
"vendor": "stripe",
"daily_usd_cap": 200,
"allowed_endpoints": ["POST /v1/payment_intents"],
"expires_in": "72h",
"label": "dify-billing-workflow"
}
Per-conversation vault keys with Dify's Chatflow API
If you're deploying Dify via its API (embedding a Chatflow in your product), you can issue a per-conversation vault key from your backend before each chat session starts. Pass the vault key as a variable into the Dify conversation context, and your Dify workflow reads it from the variable rather than from the credential store. Each user conversation gets its own independent vault key — with its own $N daily cap and its own revocable access.
# From your backend: issue vault key before starting a Dify conversation
vault_key = requests.post(
"https://api.keybrake.com/vault/keys",
headers={"Authorization": f"Bearer {KEYBRAKE_API_KEY}"},
json={
"vendor": "stripe",
"daily_usd_cap": 100,
"allowed_endpoints": ["POST /v1/payment_intents"],
"expires_in": "2h",
"label": f"dify-chat-{user_id}-{session_id}",
}
).json()["vault_key"]
# Pass it as a Dify conversation variable
dify_response = requests.post(
f"{DIFY_API_URL}/chat-messages",
headers={"Authorization": f"Bearer {DIFY_APP_KEY}"},
json={
"inputs": {"stripe_vault_key": vault_key},
"query": user_message,
"conversation_id": conversation_id,
}
)
How Keybrake fits
Keybrake is the proxy. You point your Dify tool configuration at proxy.keybrake.com and use a vault key instead of the raw vendor key. Vault keys carry a daily_usd_cap, an endpoint allowlist, and an expiry. The Free tier covers 1,000 proxied requests/month with one vendor; Hobby ($29/month) adds Stripe, Twilio, and Resend with 30-day audit log retention.
Related questions
Does this work with Dify's self-hosted deployment?
Yes. The proxy is an external HTTPS endpoint — it doesn't matter whether your Dify instance is cloud-hosted or self-hosted. As long as your Dify deployment can reach proxy.keybrake.com over HTTPS (which it can from any server with internet access), the integration works identically. Self-hosted Dify users often have stricter security requirements, so the audit log and per-run revoke are particularly useful for on-premise deployments.
What happens in the Dify UI when the proxy blocks a call?
The proxy returns a standard 429 Too Many Requests HTTP response. Dify's HTTP Request node treats this as a node error and surfaces it in the workflow execution log. If you're running an Agent workflow, the model sees the tool error in its context and can inform the user that the daily limit was reached. You can also configure a Keybrake webhook alert that fires when a cap is hit — before the 429 — to notify your team via Slack or email.
Can I use one vault key for multiple Dify workflows?
Yes — a vault key can be shared across workflows if they should share a daily cap. For example, if you have three Dify workflows that all call Stripe and you want a combined daily limit of $500 across all three, you'd use one vault key with "daily_usd_cap": 500 in all three workflows. If you want each workflow to have an independent $500 cap, issue separate vault keys for each. The granularity is your choice at vault key creation time.
Further reading
- AI agent Stripe spend cap — why Stripe's native controls don't cap per-agent spend and how pre-charge enforcement works.
- AI agent governance tools — a broader view of the tool set for controlling autonomous agents in production.
- AI agent audit trail — the schema and SQL queries for a queryable per-call log with conversation context.
- Resend AI agent API key — the same vault-key pattern applied to Resend email sends with per-conversation send caps.