<?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: Mohamed Sherif</title>
    <description>The latest articles on DEV Community by Mohamed Sherif (@m_v2n2x).</description>
    <link>https://dev.to/m_v2n2x</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%2F4046953%2F163e9705-beb5-4a77-805e-c23f9116ec1e.png</url>
      <title>DEV Community: Mohamed Sherif</title>
      <link>https://dev.to/m_v2n2x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/m_v2n2x"/>
    <language>en</language>
    <item>
      <title>How We Solved Agent Auth Without a Single PAT</title>
      <dc:creator>Mohamed Sherif</dc:creator>
      <pubDate>Sat, 25 Jul 2026 17:12:48 +0000</pubDate>
      <link>https://dev.to/m_v2n2x/how-we-solved-agent-auth-without-a-single-pat-1fnd</link>
      <guid>https://dev.to/m_v2n2x/how-we-solved-agent-auth-without-a-single-pat-1fnd</guid>
      <description>&lt;p&gt;A TOFU-based authorization model for headless AI agents&lt;/p&gt;

&lt;p&gt;By Mohamed Sherif&lt;/p&gt;

&lt;p&gt;If you’ve built an AI agent recently, you’ve probably run into the same problem.&lt;/p&gt;

&lt;p&gt;The first integration is easy.&lt;/p&gt;

&lt;p&gt;Your agent needs access to GitHub, so you create a Personal Access Token (PAT), add it to .env, and move on.&lt;/p&gt;

&lt;p&gt;GITHUB_PAT=ghp_xxxxxxxxxxxx&lt;/p&gt;

&lt;p&gt;Then you add Slack.&lt;/p&gt;

&lt;p&gt;SLACK_BOT_TOKEN=xoxb-xxxxxxxxxxxx&lt;/p&gt;

&lt;p&gt;Then Notion.&lt;/p&gt;

&lt;p&gt;NOTION_TOKEN=secret_xxxxxxxxxxxx&lt;/p&gt;

&lt;p&gt;Then Linear.&lt;/p&gt;

&lt;p&gt;LINEAR_API_KEY=lin_api_xxxxxxxxxxxx&lt;/p&gt;

&lt;p&gt;Before long your AI agent depends on a growing collection of long-lived credentials scattered across local environments, CI/CD pipelines, Kubernetes secrets, and production infrastructure.&lt;/p&gt;

&lt;p&gt;It works.&lt;/p&gt;

&lt;p&gt;Until it doesn’t.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;The Problem Every Agent Builder Eventually Hits&lt;/p&gt;

&lt;p&gt;Traditional software authenticates users.&lt;/p&gt;

&lt;p&gt;AI agents authenticate themselves.&lt;/p&gt;

&lt;p&gt;That’s a subtle but important difference.&lt;/p&gt;

&lt;p&gt;OAuth was designed around a human sitting in front of a browser who can click Allow when an application requests access.&lt;/p&gt;

&lt;p&gt;AI agents don’t have browsers.&lt;/p&gt;

&lt;p&gt;They don’t have users.&lt;/p&gt;

&lt;p&gt;They don’t have anyone available to approve access while they’re running.&lt;/p&gt;

&lt;p&gt;Most developers eventually fall back to one of four patterns.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Personal Access Tokens&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fastest to build.&lt;/p&gt;

&lt;p&gt;Also the easiest way to accumulate technical debt.&lt;/p&gt;

&lt;p&gt;You end up with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;long-lived secrets&lt;/li&gt;
&lt;li&gt;credentials living in runtime memory&lt;/li&gt;
&lt;li&gt;manual rotation&lt;/li&gt;
&lt;li&gt;no attribution&lt;/li&gt;
&lt;li&gt;difficult incident response&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Custom OAuth&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The “proper” solution.&lt;/p&gt;

&lt;p&gt;For every provider you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;register OAuth applications&lt;/li&gt;
&lt;li&gt;handle callbacks&lt;/li&gt;
&lt;li&gt;encrypt refresh tokens&lt;/li&gt;
&lt;li&gt;refresh access tokens&lt;/li&gt;
&lt;li&gt;manage expirations&lt;/li&gt;
&lt;li&gt;build consent flows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repeat this for every integration.&lt;/p&gt;

&lt;p&gt;Your authentication layer quickly becomes larger than the product you’re actually trying to build.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Secrets Managers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;AWS Secrets Manager, Vault, Azure Key Vault…&lt;/p&gt;

&lt;p&gt;These solve storage.&lt;/p&gt;

&lt;p&gt;They don’t solve authorization.&lt;/p&gt;

&lt;p&gt;Someone still has to provision credentials.&lt;/p&gt;

&lt;p&gt;The agent still eventually receives them.&lt;/p&gt;

&lt;p&gt;There’s still no approval workflow and no way to distinguish one agent from another.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Service Accounts&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Convenient.&lt;/p&gt;

&lt;p&gt;But every agent sharing that account effectively becomes the same identity.&lt;/p&gt;

&lt;p&gt;If one agent is compromised, every workload using that service account is affected.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;What We Actually Wanted&lt;/p&gt;

&lt;p&gt;After looking at these approaches, we realized we wanted something fundamentally different.&lt;/p&gt;

&lt;p&gt;Our requirements were surprisingly simple.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agents should never receive long-lived credentials.&lt;/li&gt;
&lt;li&gt;Humans should approve new agents exactly once.&lt;/li&gt;
&lt;li&gt;Every action should be attributable to a specific agent.&lt;/li&gt;
&lt;li&gt;Revoking one agent shouldn’t impact every other deployment.&lt;/li&gt;
&lt;li&gt;Existing agent frameworks shouldn’t need to change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination turned out to be harder than expected.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Borrowing an Idea from SSH&lt;/p&gt;

&lt;p&gt;The breakthrough came from an unexpected place.&lt;/p&gt;

&lt;p&gt;SSH solved a very similar problem years ago.&lt;/p&gt;

&lt;p&gt;The first time you connect to a server, SSH asks:&lt;/p&gt;

&lt;p&gt;“Do you trust this host?”&lt;/p&gt;

&lt;p&gt;If you approve it, the server fingerprint is remembered.&lt;/p&gt;

&lt;p&gt;Future connections are automatic.&lt;/p&gt;

&lt;p&gt;If the fingerprint changes unexpectedly, SSH warns you.&lt;/p&gt;

&lt;p&gt;This model is called Trust On First Use (TOFU).&lt;/p&gt;

&lt;p&gt;We asked ourselves:&lt;/p&gt;

&lt;p&gt;What if AI agents worked the same way?&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Applying TOFU to AI Agents&lt;/p&gt;

&lt;p&gt;Instead of trusting a server fingerprint, we trust an agent fingerprint.&lt;/p&gt;

&lt;p&gt;The first time an unknown agent requests access to a connected service:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The gateway pauses the request.&lt;/li&gt;
&lt;li&gt;The owner receives an approval notification.&lt;/li&gt;
&lt;li&gt;The owner approves (or rejects) the agent.&lt;/li&gt;
&lt;li&gt;The fingerprint is stored.&lt;/li&gt;
&lt;li&gt;Future requests from that fingerprint proceed automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Visually, the flow looks like this:&lt;/p&gt;

&lt;p&gt;Developer connects GitHub once&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Gateway stores OAuth credential&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Developer gives agent one Passkey URL&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Agent requests GitHub access&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Unknown fingerprint?&lt;br&gt;
        │&lt;br&gt;
   Yes ─────────► Human approval&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Fingerprint trusted&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Short-lived token exchanged&lt;br&gt;
        │&lt;br&gt;
        ▼&lt;br&gt;
Agent calls GitHub&lt;/p&gt;

&lt;p&gt;The important distinction is what the agent doesn’t receive.&lt;/p&gt;

&lt;p&gt;It never sees:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OAuth refresh tokens&lt;/li&gt;
&lt;li&gt;Personal Access Tokens&lt;/li&gt;
&lt;li&gt;stored credentials&lt;/li&gt;
&lt;li&gt;client secrets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead, it receives a short-lived token for the current session.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Fingerprints Instead of Secrets&lt;/p&gt;

&lt;p&gt;Every agent has an identity.&lt;/p&gt;

&lt;p&gt;Rather than identifying it with a shared secret, we derive a fingerprint from characteristics of its runtime.&lt;/p&gt;

&lt;p&gt;That fingerprint becomes the identity we authorize.&lt;/p&gt;

&lt;p&gt;This enables several useful properties.&lt;/p&gt;

&lt;p&gt;Attribution&lt;/p&gt;

&lt;p&gt;Every API request can be tied back to one specific agent identity.&lt;/p&gt;

&lt;p&gt;Audit&lt;/p&gt;

&lt;p&gt;You know exactly which agent accessed which service and when.&lt;/p&gt;

&lt;p&gt;Revocation&lt;/p&gt;

&lt;p&gt;Deleting one trusted fingerprint immediately blocks that agent without rotating credentials or redeploying infrastructure.&lt;/p&gt;

&lt;p&gt;Blast Radius Reduction&lt;/p&gt;

&lt;p&gt;A compromised agent only affects itself.&lt;/p&gt;

&lt;p&gt;Not every deployment using the same credentials.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;What Integration Looks Like&lt;/p&gt;

&lt;p&gt;Connecting a service happens once through the dashboard.&lt;/p&gt;

&lt;p&gt;After OAuth completes, the credential stays inside the gateway.&lt;/p&gt;

&lt;p&gt;The agent configuration remains extremely small.&lt;/p&gt;

&lt;p&gt;{&lt;br&gt;
  "mcpServers": {&lt;br&gt;
    "passkey": {&lt;br&gt;
      "command": "npx",&lt;br&gt;
      "args": ["passkey-mcp"]&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;From the perspective of LangChain, CrewAI, Strands, Bedrock AgentCore—or any MCP-compatible framework—nothing changes.&lt;/p&gt;

&lt;p&gt;The agent simply discovers tools like:&lt;/p&gt;

&lt;p&gt;github_&lt;em&gt;list_issues&lt;br&gt;
github&lt;/em&gt;&lt;em&gt;create_comment&lt;br&gt;
slack&lt;/em&gt;&lt;em&gt;post_message&lt;br&gt;
linear&lt;/em&gt;&lt;em&gt;create_issue&lt;br&gt;
notion&lt;/em&gt;_query_database&lt;/p&gt;

&lt;p&gt;The authentication layer becomes invisible.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Why We Chose Token Exchange&lt;/p&gt;

&lt;p&gt;One design decision deserves explanation.&lt;/p&gt;

&lt;p&gt;Instead of proxying every request, the gateway performs a token exchange.&lt;/p&gt;

&lt;p&gt;Once authorized, the agent receives a short-lived upstream token.&lt;/p&gt;

&lt;p&gt;The API traffic then goes directly to the provider.&lt;/p&gt;

&lt;p&gt;That provides several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lower latency&lt;/li&gt;
&lt;li&gt;no gateway bottleneck&lt;/li&gt;
&lt;li&gt;no proprietary protocol&lt;/li&gt;
&lt;li&gt;compatibility with existing MCP tooling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Other Design Decisions&lt;/p&gt;

&lt;p&gt;Rotating Connection URLs&lt;/p&gt;

&lt;p&gt;Connection URLs use rotating slugs.&lt;/p&gt;

&lt;p&gt;Capturing yesterday’s URL isn’t enough to gain access.&lt;/p&gt;

&lt;p&gt;It must also match a trusted fingerprint.&lt;/p&gt;

&lt;p&gt;Dynamic Client Registration&lt;/p&gt;

&lt;p&gt;Where supported, every customer receives their own OAuth client rather than sharing one across the platform.&lt;/p&gt;

&lt;p&gt;That reduces rate-limit contention and isolates failures between organizations.&lt;/p&gt;

&lt;p&gt;MCP-Native&lt;/p&gt;

&lt;p&gt;Rather than invent another SDK, we built around MCP.&lt;/p&gt;

&lt;p&gt;Any framework that already supports MCP can use the same authentication model without additional integration work.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;When This Approach Makes Sense&lt;/p&gt;

&lt;p&gt;This model is particularly useful if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your agent talks to multiple SaaS platforms&lt;/li&gt;
&lt;li&gt;you’re deploying beyond prototypes&lt;/li&gt;
&lt;li&gt;credential management has become operational overhead&lt;/li&gt;
&lt;li&gt;you need attribution and auditability&lt;/li&gt;
&lt;li&gt;security teams don’t want PATs spread throughout infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re building a weekend project with one integration, a PAT is probably sufficient.&lt;/p&gt;

&lt;p&gt;Once multiple integrations and production deployments enter the picture, the trade-offs begin to change.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;Try It&lt;/p&gt;

&lt;p&gt;If you’re interested in experimenting with this model, install the local broker:&lt;/p&gt;

&lt;p&gt;npx passkey-mcp&lt;/p&gt;

&lt;p&gt;Then manage everything through:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://dashboard.v2n2x.com" rel="noopener noreferrer"&gt;https://dashboard.v2n2x.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connect your first OAuth provider through the Passkey dashboard, then point any MCP-compatible agent at it.&lt;/p&gt;

&lt;p&gt;Today the platform supports 19 integrations including GitHub, Slack, Jira, Confluence, Notion, Stripe, Salesforce, HubSpot, and Linear.&lt;/p&gt;

&lt;p&gt;I’d love to hear feedback from developers building production AI agents.&lt;/p&gt;

&lt;p&gt;The biggest question we wanted to answer was simple:&lt;/p&gt;

&lt;p&gt;Can we eliminate long-lived credentials from AI agents without making developer experience worse?&lt;/p&gt;

&lt;p&gt;So far, the answer has been yes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>headless</category>
    </item>
  </channel>
</rss>
