theAuth for AI Agents: Identity and Scoped Permissions A developer released theAuth, an open-source TypeScript library (@glinr/theauth) that gives each AI agent its own identity, token, and scoped permissions instead of sharing a human's API key. The guide walks through creating per-agent `kv_` tokens, calling `authorize()` before every action for allow/deny decisions with audit IDs, adding rate limits and argument constraints, delegating narrower scopes to sub-agents, and revoking one agent without affecting others. theAuth is open-source auth for AI agents and humans. Star the repo on GitHub https://github.com/glincker/theauth · Read the docs https://docs.theauth.dev?utm source=devto&utm medium=article&utm campaign=guide-5-ai-agent-identity-scoped-permissions · Run the quickstart https://docs.theauth.dev/quickstart?utm source=devto&utm medium=article&utm campaign=guide-5-ai-agent-identity-scoped-permissions · theauth.dev https://theauth.dev?utm source=devto&utm medium=article&utm campaign=guide-5-ai-agent-identity-scoped-permissions Last spring I found one API key in four places. It sat in a cron job, a Slack bot, a code-review agent, and a notebook a teammate had forgotten about. The key belonged to a human. It could read everything that human could read, and it could write most of it too. Nothing was wrong yet. Then I asked a simple question: which of the four did that delete last Tuesday? I could not answer it. The logs said the human did it. That is the problem this guide fixes. You will give each AI agent its own identity, its own token, and a short list of things it may do. By the end you will have a runnable script that creates agents, denies the wrong calls, logs every decision, and revokes one agent without touching the others. I use theAuth for this, an open-source TypeScript library @glinr/theauth . I wrote parts of it, so weigh my opinions accordingly. I will say plainly where it does not fit. This is guide 5 of 8 in the theAuth guides. It stands on its own, so you can start right here. Nothing comes before it. It is the base for guides 6 to 8. | Guide | Title | Read it when | |---|---|---| | 1 | Add login to an existing Next.js app https://dev.to/thegdsks/add-login-to-an-existing-nextjs-app-with-theauth-4kpk | You have an app with no auth yet | | 2 | Passwordless login: passkeys, links, OTP https://dev.to/thegdsks/passwordless-login-in-typescript-passkeys-links-otp-59ja | You want to drop passwords or add 2FA | | 3 | Multi-tenant SaaS auth: orgs, RBAC, SSO, SCIM https://dev.to/thegdsks/multi-tenant-saas-auth-orgs-rbac-sso-and-scim-1fod | You sell to teams and companies | | 4 | Migrate from Auth0 or Clerk https://dev.to/thegdsks/migrate-from-auth0-or-clerk-to-theauth-step-by-step-4o47 | You already run another provider | | 5 | Give every AI agent its own identity this guide | You run AI agents and need to start somewhere | | 6 | Cap agent spend and require human approval https://dev.to/thegdsks/cap-agent-spend-and-require-human-approval-in-typescript-2k9h | Your agents spend money or act on risky things | | 7 | Secure an MCP server for production https://dev.to/thegdsks/securing-an-mcp-server-for-production-step-by-step-53h7 | You expose tools over MCP | | 8 | Build an audit trail for AI agent actions https://dev.to/thegdsks/build-an-audit-trail-for-ai-agent-actions-23j7 | Someone will ask what your agents did | Building for people? Start at guide 1. Building for AI agents? Start at guide 5. Every guide links to the docs page for each concept it touches. | Step | What you do | Result | |---|---|---| | 1 | Install and create an instance | A local SQLite database with agents enabled | | 2 | Seed an owner | One human row that agents hang off | | 3 | Create one agent per job | A kv token per agent, shown once | | 4 | Call authorize before every action | An allow or deny with an audit ID | | 5 | Add constraints | Rate limits, argument patterns, time windows | | 6 | Check tokens in middleware | 401 and 403 at your HTTP edge | | 7 | Delegate to sub-agents | A narrower scope, with an expiry | | 8 | Read the audit trail, rotate, revoke | Answers to "which agent did that" | You need Node 20 or newer, TypeScript, and a package manager. You do not need a running server or an external database. The examples use SQLite on disk so you can open the file afterward. You also need one honest assumption: the agents in your system call tools you control. theAuth gives you the decision point. Your code must ask it before acting. If an agent can reach a database directly with its own credentials, no permission list in the world will stop it. A shared human key has three problems, and they stack. First, the blast radius equals the human's permissions. A code reviewer that only needs to read pull requests inherits write access to everything. Second, you cannot revoke one agent. Rotate the key and all four processes break at once. You wait, and the exposed key stays live. Third, the audit trail lies. Every row names the human. Your compliance questions, and your own debugging, hit a wall. A per-agent identity fixes all three. Each agent holds a token that maps to one row, one owner, and one permission list. The core concepts page https://docs.theauth.dev/concepts describes the loop in one sentence: a user creates agents, agents call authorize before acting, and every decision lands in the audit trail. One distinction matters early. An agent is not a user. It has no email, no password, no session, and no OAuth account. It has a bearer token and a permission set. If you catch yourself wiring password reset for an agent, you want a user. The agent identity page https://docs.theauth.dev/agents draws that line. mkdir agent-identity-demo && cd agent-identity-demo npm init -y npm install @glinr/theauth npm install -D tsx typescript Now create demo.ts . I will build it up one piece at a time, and the full file is the sum of the blocks below. js import { createTheAuth } from '@glinr/theauth'; const theauth = await createTheAuth { database: { provider: 'sqlite', url: 'theauth.db' }, agents: { enabled: true, maxPerUser: 10, auditAll: true, tokenExpiry: '24h', }, } ; Two settings deserve a note. auditAll records every authorize call, and it defaults to on. tokenExpiry sets how long a new agent lives when you do not pass expiresAt . A 24 hour default means an agent you forget about stops working by tomorrow. I like that default. A forgotten credential should expire, not linger. The quickstart walks through the same setup if you want the scaffolded Next.js version instead: https://docs.theauth.dev/quickstart https://docs.theauth.dev/quickstart . Every agent has an owner, and the owner must exist as a row in theauth users . That column is a foreign key. Skip this step and you will see FOREIGN KEY constraint failed on your first create call. Everyone hits it once. If you already run theAuth's own auth modules, sign-up creates the row for you. In a scratch script, insert one: js import { users } from '@glinr/theauth'; theauth.db.insert users .values { id: 'user-1', email: 'owner@example.com', name: 'Owner', createdAt: new Date , updatedAt: new Date , } .run ; This insert pattern comes from the quickstart troubleshooting section and works for SQLite. For Postgres, the database docs list the matching call. Here is the rule I follow: one agent per job, not one agent per person. A nightly pull-request reviewer and a refund bot should never share an identity, even if the same human set up both. js const reviewer = await theauth.agent.create { ownerId: 'user-1', name: 'pr-reviewer', type: 'autonomous', permissions: { resource: 'mcp:github: ', actions: 'read' }, , expiresAt: new Date Date.now + 7 24 3 600 000 , metadata: { purpose: 'nightly PR review' }, } ; const refunder = await theauth.agent.create { ownerId: 'user-1', name: 'refund-bot', type: 'autonomous', permissions: { resource: 'billing:refunds', actions: 'read', 'write' }, , } ; console.log reviewer.token ; // kv ..., shown once The token starts with kv , followed by 32 random bytes in base64url, 46 characters in total. theAuth stores only the SHA-256 hash. A full database dump cannot reveal a live token. That has a cost. You see the plaintext exactly once, at creation. Put it in your secrets manager before the process exits, or rotate to get a new one. You cannot recover it later. The type field takes three values. An autonomous agent runs on its own, with no approval step unless a permission constraint demands one. Cron jobs and unattended assistants fit here. This is the default choice. A delegated agent receives its permissions from another agent through a delegation chain. Use it for short-lived workers spun up for one task. A service agent is a long-lived identity for infrastructure, such as an MCP server or an internal microservice. Treat it like a service account. By default one user can own 10 active agents. The eleventh create call throws a plain Error with the message User