<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: fcn06</title>
    <description>The latest articles on DEV Community by fcn06 (@fcn06).</description>
    <link>https://dev.to/fcn06</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4070178%2F49cf50bd-9c2a-40ed-a404-8ed0b8345aeb.png</url>
      <title>DEV Community: fcn06</title>
      <link>https://dev.to/fcn06</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fcn06"/>
    <language>en</language>
    <item>
      <title>Stop Giving AI Agents Your API Keys: Introducing Trust Gateway (WIP)</title>
      <dc:creator>fcn06</dc:creator>
      <pubDate>Mon, 10 Aug 2026 15:44:10 +0000</pubDate>
      <link>https://dev.to/fcn06/stop-giving-ai-agents-your-api-keys-introducing-trust-gateway-wip-1c8f</link>
      <guid>https://dev.to/fcn06/stop-giving-ai-agents-your-api-keys-introducing-trust-gateway-wip-1c8f</guid>
      <description>&lt;p&gt;AI agents are getting increasingly capable at calling tools: issuing refunds, updating tickets, sending emails, modifying infrastructure, querying databases, and triggering deployment pipelines.&lt;/p&gt;

&lt;p&gt;But there’s a security problem I kept coming back to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why should the agent itself possess the credentials needed to perform those actions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an agent has a Stripe key, GitHub token, cloud credential, or database password, then the security boundary is effectively inside the agent runtime.&lt;/p&gt;

&lt;p&gt;I wanted to see if there was a cleaner way to decouple intent from execution, so I started building a small side project called &lt;strong&gt;Trust Gateway&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s very much a work in progress, and I’m sharing it early to get feedback from the community on the core design, hear how others are approaching this, and learn where it can be improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The idea&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Trust Gateway separates &lt;strong&gt;proposing an action&lt;/strong&gt; from &lt;strong&gt;having authority to execute it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The model is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agents propose. Gateway decides. Executors verify.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of giving an AI agent a downstream API key, the agent submits a structured &lt;code&gt;ProposedAction&lt;/code&gt; to the gateway.&lt;/p&gt;

&lt;p&gt;The gateway evaluates that action against policy.&lt;/p&gt;

&lt;p&gt;If it is allowed, the gateway issues a short-lived, cryptographically signed &lt;code&gt;ExecutionGrant&lt;/code&gt; bound to the exact tool and parameters that were approved.&lt;/p&gt;

&lt;p&gt;The gateway dispatches the granted action to the appropriate executor. Before any side effect, the executor independently verifies the grant's signature, expiry, audience, tool binding, argument hash, and single-use nonce.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────┐       ProposedAction       ┌───────────────┐
│  AI Agent  │ ─────────────────────────▶ │ Trust Gateway │
└────────────┘                            └───────┬───────┘
                                                │
      No downstream credentials                 │ GrantedAction
                                                │ + ExecutionGrant
                                                ▼
                                        ┌───────────────┐
                                        │   Executor    │
                                        │ owns API key  │
                                        └───────┬───────┘
                                                │
                                                ▼
                                               API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that the executor does &lt;strong&gt;not&lt;/strong&gt; trust the agent when it says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This action was approved.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It verifies the authorization itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why I think this matters&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Imagine an agent with a tool like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stripe.refund(  
    payment_id="...",  
    amount=50000  
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are several possible policies you might want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading a customer record → automatically allowed
&lt;/li&gt;
&lt;li&gt;Refunding €5 → automatically allowed
&lt;/li&gt;
&lt;li&gt;Refunding €500 → requires human approval
&lt;/li&gt;
&lt;li&gt;Refunding €50,000 → always denied
&lt;/li&gt;
&lt;li&gt;Calling a tool with unexpected parameters → denied&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But even if you implement those policies inside your agent framework, the agent may still hold the credential that bypasses them.&lt;/p&gt;

&lt;p&gt;Trust Gateway moves that authorization boundary outside the agent.&lt;/p&gt;

&lt;p&gt;The agent can ask.&lt;/p&gt;

&lt;p&gt;It cannot simply decide.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What an integration looks like&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The Python SDK lets you guard a tool using a decorator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;trust_gateway.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrustGatewayClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;guard_tool&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TrustGatewayClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dev_mode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="n"&gt;gateway_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3060&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@guard_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stripe_refund&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_refund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refunded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;  
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when an agent attempts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;process_refund(  
    amount=500,  
    order_id="ord_123"  
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the function is not automatically executed.&lt;/p&gt;

&lt;p&gt;Trust Gateway first evaluates the proposed action.&lt;/p&gt;

&lt;p&gt;A policy can return something like:&lt;/p&gt;

&lt;p&gt;require_approval&lt;/p&gt;

&lt;p&gt;and no execution grant is issued until the required approval exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Execution grants&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I wanted authorization to be independently verifiable, rather than just another HTTP response saying &lt;code&gt;"approved": true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So Trust Gateway defines an &lt;strong&gt;Execution Authorization Protocol&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;structured &lt;code&gt;ProposedAction&lt;/code&gt; objects
&lt;/li&gt;
&lt;li&gt;deterministic canonical JSON
&lt;/li&gt;
&lt;li&gt;SHA-256 input hashing
&lt;/li&gt;
&lt;li&gt;Ed25519 signatures
&lt;/li&gt;
&lt;li&gt;short-lived grants
&lt;/li&gt;
&lt;li&gt;single-use &lt;code&gt;jti&lt;/code&gt; nonces
&lt;/li&gt;
&lt;li&gt;grants bound to the exact tool and parameter set&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means an authorization for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{  
  "tool": "stripe_refund",  
  "amount": 500  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cannot simply be reused to execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{  
  "tool": "stripe_refund",  
  "amount": 50000  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parameters are part of what is authorized.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Human-in-the-loop without putting humans everywhere&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I also wanted HITL to be a policy decision rather than the architecture itself.&lt;/p&gt;

&lt;p&gt;Not every tool call should trigger a Slack message asking someone to click Approve.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;search_docs          → allow&lt;br&gt;&lt;br&gt;
read_customer        → allow&lt;br&gt;&lt;br&gt;
send_email           → require approval&lt;br&gt;&lt;br&gt;
stripe_refund &amp;lt; $20  → allow&lt;br&gt;&lt;br&gt;
stripe_refund &amp;gt;= $20 → require approval&lt;br&gt;&lt;br&gt;
delete_database      → deny&lt;/p&gt;

&lt;p&gt;The gateway can distinguish between routine actions and high-impact mutations.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Quickstart&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can run it locally with Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/fcn06/trust_gateway.git
&lt;span class="nb"&gt;cd &lt;/span&gt;trust_gateway
docker compose &lt;span class="nt"&gt;-f&lt;/span&gt; deploy/docker-compose.yml up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install the Python SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; sdks/python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There’s also a standalone Docker demo if you don’t want to install Rust.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What Trust Gateway is — and isn't&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Trust Gateway isn't intended to make an LLM itself trustworthy.&lt;/p&gt;

&lt;p&gt;It also isn't a replacement for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sandboxing
&lt;/li&gt;
&lt;li&gt;IAM
&lt;/li&gt;
&lt;li&gt;secret management
&lt;/li&gt;
&lt;li&gt;network isolation
&lt;/li&gt;
&lt;li&gt;application-level authorization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, it addresses a narrower problem:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we let an autonomous or semi-autonomous agent request privileged actions without giving that agent unrestricted possession of the authority required to perform them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the security boundary I'm exploring.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Where I'd love feedback&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The project is still evolving, and I’m especially interested in feedback from people building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI agents with real side effects
&lt;/li&gt;
&lt;li&gt;MCP/tool servers
&lt;/li&gt;
&lt;li&gt;internal developer platforms
&lt;/li&gt;
&lt;li&gt;financial or support automation
&lt;/li&gt;
&lt;li&gt;agentic DevOps workflows
&lt;/li&gt;
&lt;li&gt;security infrastructure for autonomous systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’d particularly love opinions on the protocol design and threat model.&lt;/p&gt;

&lt;p&gt;GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/fcn06/trust_gateway" rel="noopener noreferrer"&gt;https://github.com/fcn06/trust_gateway&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're building agents that can do more than just generate text, I'd be curious:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where do you currently put the authorization boundary between the model and the systems it can modify?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;#ai #mcp #opensource #python&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
