Who can log in, and what can they do?
Auth and tools
Scale auth and tools
for hundreds of users, at a time.
A walkthrough. Then a live demo.
Saif Ali Shaik Founding DX Engineer · Scalekit
The frame
Auth for apps, and auth for agents.
What can the agent do, on whose behalf?
You have already seen this
Von. Linear.
A chat. Then work happens.
A live agent acting as a real user — not a service account.
02 · The problem
Every tool call carries two questions.
Proving an identity.
Scoping the permission.
Most setups answer who. Few enforce what.
03 · The cost
The m × n problem
Share one account and anyone reads anyone’s data. Scope it per user, and the credentials explode.
One shared account
Authenticated, never authorized
One credential per user, per tool
Issued, stored, and refreshed, per user, per provider
An open door or a full-time credential job. Neither ships an agent.
How we got here · 1
First came the inference API.
A manager asked. A teammate shipped it. Months ago, people started sending prompts to an LLM.
How we got here · 2
Then the script started to decide.
agent = LLM + harness
harness = tools + loop + state
An agent is a model inside a loop. The harness lets it call tools and keep state.
How we got here · 3
Some of those agents already work.
Show the repos that moved this week.
Summarize the pipeline for the standup.
See which tickets eat the week.
One shared key is enough here. A demo. A dashboard. Not a user.
How we got here · 4
Then they want their apps
in your agent.
Not your HubSpot. Theirs. GitHub. Slack. Linear. The tools they already live in.
That is when auth and tools must scale. scalekit.com/connectors
Customer story · Z47
WhatsApp + OpenClaw + Scalekit
Every agent runs in its own per-user sandbox. Scalekit owns identity, the credential vault, and every tool call. The sandbox never sees a real token.
Team chat
- Team member sends message
Router
- Looks up phone number
- Routes to user sandbox
- Spins one up if missing
- Passes message in
Per employee
- Holds client ID only
- No tokens or secrets stored
- Calls Scalekit SDK
Identity + execution
- Resolves user identity
- Fetches scoped token
- Executes tool call
- Returns result to agent
- Logs audit event
- Enforces rate limits
The hard way
You can write the OAuth yourself.
Then do it again for every app, and every user. I wrote the handbook. It is not short. freecodecamp.org/news/ai-agent-per-user-oauth-slack-github
04 · The solution
One layer for auth and tools.
It holds when you add users.
What it does
Delegated OAuth. Per-user actions.
Read a page
Create a row
Send a message
Pull a record
05 · Runtime · Next builds it
One connector. Many connections. Many accounts.
Next adds a piece · 0 / 6
05 · Runtime architecture
One connector → many connections → many accounts.
Configure a connection once. Every user who authorizes gets their own connected account.
Same connector, two auth methods. That is why connection is its own primitive.
06 · Your stack
Bring your own connectors & tools.
No token refresh logic. No auth plumbing. Scalekit injects the user’s credentials at runtime.
send_slack_message
github_pull_request_get
agent.call(
send_slack_message(channel, text)
)
Design the tool around the agent’s intent. Your code. Your contract.
{"queue_id": 42, "fields": {…}}
create_ticket(queue, summary)
Any SaaS API, internal system, or remote MCP server.
register_connector( url, auth, schema )
06 · Tool call · Next builds it
Scalekit injects the user’s credentials at runtime.
Next adds a piece · 0 / 6
In code · 1 of 3 · create the account
connectionName must match the dashboard.
// docs.scalekit.com/agentkit/quickstart const { connectedAccount } = await actions.getOrCreateConnectedAccount({ connectionName: 'github-connect', identifier: 'user_123', });
New Scalekit environments already have a GitHub connection named github-connect.
In code · 2 of 3 · user says yes
Do not call tools until status is ACTIVE.
if (connectedAccount.status !== ConnectorStatus.ACTIVE) { const { link } = await actions.getAuthorizationLink({ connectionName: 'github-connect', identifier: 'user_123', }); // redirect the user to link, then resume }
Scalekit stores the tokens. You store only the user identifier.
In code · 3 of 3 · fetch the PR
There is no summarize tool. There is a get tool.
const result = await actions.executeTool({ toolName: 'github_pull_request_get', identifier: 'user_123', connector: 'github-connect', toolInput: { owner: 'acme', repo: 'app', pull_number: 42 }, }); // result.data is the PR. Your model writes the summary.
Real tool name from docs.scalekit.com/agentkit/connectors/github
What the agent does next
Scalekit returns the PR.
Your model writes the summary.
Optional next call: github_pull_request_files_list.
07 · Scoping
Scope tools that the agent can reach.
Not just what it is allowed to do.
An inbox-summarizer agent needs one capability: fetch mail.
It gets all 30 tools on the server: send, delete, label, manage filters, manipulate threads.
A Config exposes exactly what is needed: gmail_fetch_mails.
Nothing else is reachable.
30 tools × ~200 tokens ≈ 6,000 tokens burned before the agent does anything. Scoped to the 1 tool it needs, that drops to ~200 tokens.
Then the dashboard
You will see the connected account.
The approved identity. The tool calls. The proof.
The point
You build the agent.
Scale the auth and the tools.
Saif Ali Shaik · Founding DX Engineer, Scalekit
Join the agents in production community
Our Luma
Where agent builders show up
luma.com/scalekitinc
linkedin.com/in/saif-shines