Auth Brokers · Stytch & Composio · 2026

How a Middle Service Connects Auth Between Apps

The mental model behind tools like Composio and Stytch: how one service brokers OAuth so your app — or your AI agent — can act across Gmail, Slack, GitHub and 500 others, without ever touching a raw credential. Roles, the handshake, connected accounts, token refresh, and the full architecture.

0 / 6 sections
1
Why a Middle Service? The N×M Credential Problem
Every new integration multiplies the OAuth flows, token stores, and refresh jobs you own

Say your app (or agent) needs to read a user's Gmail, post to their Slack, and open GitHub PRs for them. Each one is a separate OAuth integration: register an app with the provider, build the redirect/consent flow, securely store the returned tokens, and run a job to refresh them before they expire — per provider, per user. Add a fourth service and you do it all again.

A middle service — an auth broker like Composio (for consuming others' APIs) or Stytch (for issuing your own) — collapses that. You integrate with the broker once; it owns each provider's OAuth dance, encrypts and stores the tokens, and refreshes them silently. Your code goes from "maintain N integrations" to "call one API."

Demo — connect some services, then flip on the broker
0
OAuth flows you build & maintain
0
Token-refresh jobs you own
Click services to connect them, then toggle the mode and watch what you have to maintain.
Once you adopt an auth broker, why does adding a 5th third-party integration cost almost nothing?
2
The Four Roles in Every OAuth Handshake
Resource owner · client · authorization server · resource server — and where the broker sits

Everything a broker does is just OAuth 2.0 played well. OAuth defines four roles. The whole point is delegated access: the user lets a client act on their behalf without handing over their password — the provider issues a scoped token instead.

The mental unlock: the broker plays the "client" role. It holds the OAuth client_id/client_secret registered with each provider and drives the flow so your app or agent doesn't have to.

Demo — click each role to see who it is in "agent reads your Gmail"
Click a role card.
A scope is the leash: when the broker (client) starts the flow it asks only for what it needs — e.g. gmail.send, not mail.google.com/ full access. The provider shows the user exactly those scopes on the consent screen, and the token can never exceed them.
When the broker runs the flow so your agent can send mail as the user, which OAuth role does the broker play?
3
The Authorization-Code Flow: The Actual Handshake
From "Connect Gmail" to a stored token — one redirect, one code, one server-side exchange

This is the choreography the broker performs the first time a user connects a service. The clever bit is the authorization code: the browser only ever carries a short-lived, single-use code — the real tokens are fetched server-to-server using the client secret, so they never ride in a URL or sit in the browser.

Demo — play the flow, or click any step to inspect it
Click a step to inspect it.
// Step 5 — the broker's SERVER exchanges the code (client secret never leaves the backend)
POST https://oauth2.googleapis.com/token
{ "grant_type": "authorization_code",
  "code": "4/0Ax…single-use…",
  "client_id": "<broker's id>",
  "client_secret": "<broker's secret>" }
// → { "access_token": "ya29.…", "refresh_token": "1//0e…", "expires_in": 3599 }
The state parameter the broker sends in step 2 comes back in step 4. It ties the redirect to the request that started it — without it, an attacker could trick a user into completing a flow the attacker began (CSRF). Brokers handle this for you.
At the redirect (step 4) the provider hands back a code — not the access token. Why?
4
Connected Accounts: Where the Tokens Live (and Refresh)
One encrypted record per user-per-service — and silent refresh the agent never sees

After the handshake, the broker stores the result as a connected account: an encrypted record keyed by your user id + the service, holding the access token, the refresh token, the granted scopes, and an expiry. (Composio calls this exactly that — a "connected account"; one user can even have several on the same toolkit.)

Access tokens are deliberately short-lived (~1 hour). The magic that makes a broker feel seamless: when your agent makes a call and the token is stale, the broker silently swaps in a fresh one using the refresh token, then completes the call. The agent never handles, sees, or refreshes a token.

Demo — the broker's vault for user_42's Gmail. Make calls, expire the token, watch it self-heal
owneruser_42
toolkitgmail
access_tokenya29.a0Af_Hq3…8xQk
refresh_token1//0eXa…long-lived…rT9
scopesgmail.send
statusvalid · ~59m left
The agent just wants to "send an email." It never asks about tokens — that's the broker's job.
Security payoff. Tokens live encrypted in the broker, scoped to the minimum, and are revocable per connected account. A leak in your app code exposes no long-lived provider credentials — your code only ever held a broker handle, never Google's refresh token.
An agent calls "send email," but the stored access token expired 5 minutes ago. With a good broker, what happens?
5
Two Directions: Consuming APIs vs. Becoming the Provider
Composio holds tokens to call others for you · Stytch makes your app the OAuth provider

"Middle service" covers two mirror-image jobs. Both broker OAuth — but the tokens flow in opposite directions, and that's the cleanest way to tell Composio and Stytch apart.

Your agent wants to act on other services. The broker holds the downstream tokens (from Gmail, Slack, GitHub…) and exposes them as clean, typed tools your LLM can call. This is the Composio model: managed auth for 500+ apps, just-in-time tool calls, native function calling.

🤖
Your Agent
calls a tool
🧩
Composio
holds user's tokens
🌐
Gmail / Slack / GitHub
others' APIs
The agent never sees a token — it just calls GMAIL_SEND_EMAIL and the broker does the rest.

You flip around and let others act on you. With Stytch Connected Apps, your app becomes a fully compliant OAuth 2.0 / OIDC provider — so other apps (and AI agents over MCP) get a "Log in with Your App" button and you issue them scoped tokens. Stytch runs the authorization-code handling, JWT issuance/verification via JWKS, refresh, and revocation.

🧠
Their Agent / App
"Log in with You"
🛂
Stytch + Your App
issues tokens
📬
Your API
scoped access
Now you are the authorization server from Section 2 — issuing tokens others present to your API.
Same protocol, opposite vantage point. Consuming: the broker is a client to many providers. Providing: the broker turns you into the provider. Plenty of stacks use both — consume others' tools and expose your own.
What's the core architectural difference between Composio and Stytch Connected Apps?
6
The Full Architecture, End to End
"Post to Slack" → broker resolves the connected account, handles the token, calls the API

Put the pieces together. The agent issues a plain intent ("post this to Slack"). The broker splits into two responsibilities you saw earlier: an auth layer that resolves which connected account to use and refreshes its token if stale (Sections 3–4), and the outbound call to the real service API. The agent holds no secret — only a broker handle + the target user id.

Hover each component for its job, then hit Play full flow.
Demo — one request, end to end
🤖
Agent / App
"post to Slack"
Calls a typed tool with a plain intent and the target user id. Never sees a client secret or a provider token — it only holds a broker API key.
🧩
Auth Broker
resolves + authorizes
Looks up the connected account for (user_42, slack), checks scopes, and decides whether the access token is still valid. Holds the OAuth client_id/secret for each provider.
🗄️
Token Vault
encrypted tokens
Stores access + refresh tokens encrypted, keyed per user-per-service. If the access token expired, the broker uses the refresh token here to mint a fresh one — silently.
🌐
Service API
Slack
The resource server. Accepts the bearer access token, performs the action (chat.postMessage), and returns the result — which the broker passes back to the agent.
Hover a component, or play the flow.
The broker is now your blast radius. Since it concentrates every user's tokens for every service, treat your broker API key like a master key — scope it, rotate it, and never ship it to a browser or an untrusted agent. Per-user scoping in the broker limits what any single key or session can reach.
When the agent says "post to Slack," what does the agent itself actually send and receive?

🧩 You've got the broker model

One integration replaces N. OAuth's four roles → the code flow → connected accounts + silent refresh → consume (Composio) or provide (Stytch) → an agent that acts everywhere and holds nothing.

Learning Reference · Composio — Managed Authentication · Stytch — Connected Apps · RFC 6749 — OAuth 2.0

Get new posts in your inbox

No spam — just new posts and learning pages when they ship.

Share X LinkedIn Reddit Hacker News