Sit where the API sits
Alice types a question into your agent: what’s on my calendar tomorrow? The agent decides to call the calendar API. From where you sit, nothing could be clearer. Alice asked, and the agent is fetching Alice’s events for Alice.
Now sit where the calendar API sits. It receives an HTTP request. It cannot see Alice. It cannot see the conversation, the model or your code. It sees the request, and whatever came attached to it.
That attachment is called a credential, and it is the only evidence the API has. A credential can prove up to three things:
- Who is acting? Which piece of software the credential was given to.
- For whom? Which person it is working for, if any.
- Who said they could? What was approved, and by whom.
Try three credentials
Here are three things your agent could attach. Before you try them, make a guess: which of them lets the API tell a request for Alice from a request for Bob?
The agent attaches: Its own API key
What arrives at the API
GET /events?day=tomorrow HTTP/1.1
Host: calendar.example
X-API-Key: sk_agent_7f3a9c…
X-User: alice| Who is acting? | Yes | The key belongs to the agent’s account. |
|---|---|---|
| For whom? | No | alice is whatever the agent typed. The API cannot confirm it. |
| Who said they could? | No | An administrator gave the agent its access. Alice approved nothing. |
The API knows the agent is calling, and has to take its word for everything else. If Bob asks for Alice’s calendar and the agent sends Alice’s name, the API sees a valid key and answers. Alice is protected only while the agent tells the truth about who is asking. Do not rely on a key to keep users apart.
The agent attaches: A key Alice made
What arrives at the API
GET /events?day=tomorrow HTTP/1.1
Host: calendar.example
X-API-Key: sk_user_2b9e41d…| Who is acting? | No | The key is Alice’s. Nothing shows which software is using it, or that software is involved at all. |
|---|---|---|
| For whom? | Yes | Alice’s account, because the key is hers. |
| Who said they could? | Partly | Alice made the key, so she agreed to something. Most keys open the whole account and never expire. |
The API can now tell Alice’s requests from Bob’s. But as far as it can tell, the agent is Alice: whatever it does is recorded as her doing it, and the key usually allows everything her account can do, for as long as it exists. It names the person and hides the software.
The agent attaches: A token Alice approved
What arrives at the API
GET /events?day=tomorrow HTTP/1.1
Host: calendar.example
Authorization: Bearer eyJhbGciOiJFUzI1NiIs…What the token says, once the API has checked it
for: alice
issued to: calendar-assistant
allows: read the calendar
signed by: auth.example| Who is acting? | Yes | The token names the app it was issued to. Like a key, it works for whoever holds a copy. |
|---|---|---|
| For whom? | Yes | The token names Alice, and the service that signed it vouches for that. |
| Who said they could? | Yes | Alice did, for reading her calendar and nothing else. |
The API can now tell Alice’s requests from Bob’s, refuse anything beyond reading a calendar, and block this one agent without locking Alice out. What the agent can do for Alice is now limited by what Alice approved, and the API is the one enforcing it.
| The agent attaches | Who is acting? | For whom? | Who said they could? |
|---|---|---|---|
| Its own API key | Yes | No | No |
| A key Alice made | No | Yes | Partly |
| A token Alice approved | Yes | Yes | Yes |
Where the two keys fall short
An API key is what most of us reach for first. For a program with one owner it can be enough, as long as the key is kept where the model cannot read it and can do no more than the job needs. The trouble starts when one agent works for many people. One key is one identity, so every request looks the same to the API, whoever asked. The agent can add a name to the request, and the API can apply its rules to that name. But a name the sender typed is a claim, not evidence: the API is still taking the agent’s word for whose request this is.
In an agent that name is often filled in by the model, so text the model has read can choose whose data is fetched. Where an API offers nothing but a key, your own code has to set the user from its signed-in session, never from anything the model wrote, and check each request against that user before the key is used.
Having Alice make a key of her own and hand it over fails the other way. The API now knows whose account this is, and nothing else. It cannot tell your agent from Alice herself, or from anything else that holds the key, so everything the agent does is recorded as her doing it. Most such keys open the whole account and last until someone remembers to delete them.
And Alice had to copy a secret by hand. If she pasted it into the conversation, the model has read it, and anything the model has read it can be asked to repeat. So never ask a user to paste a secret into a conversation: not a key, not a token, and above all not a password, which the agent must never see at all. Lesson 3 is about how that is arranged.
Both failures matter more for an agent than for an ordinary program, because an agent can be talked into things. It reads web pages, emails and documents, and any of them may contain text written to steer it. If the agent’s key can read everyone’s calendar, one successful trick reads everyone’s calendar.
So one rule runs through this whole guide. A limit that lives in the agent, or in its prompt, is a suggestion. A limit the API enforces, using evidence the agent cannot make up, is a control.
What the token changes
The third credential is a different kind of thing. The agent did not write it. A service the API already trusts wrote it and signed it, after asking Alice. It says who it is for, which app it was given to and what it allows, and the API can check all of that without taking the agent’s word for anything.
How a few lines of text manage that is the next lesson. One caution to carry with you. A “yes” under who is acting means the credential names the software it was given to. None of the three shows that the software sending it is that one: a key and a token share a weakness, and each works for whoever holds a copy. The next lesson shows that happen, and the final lesson shows what can be done about it.
Check yourself
Answer before you read on. Nothing is recorded.
What to keep
- An API sees a request and a credential. It does not see the user, the conversation or the intent.
- A credential is worth what it proves: who is acting, for whom, and who said they could.
- The agent’s own key proves the first. A key the user made proves the second. A token the user approved can carry all three.
- A limit only counts where the agent cannot talk its way around it. That place is the API.
One rule
Never ask a user to paste a secret into the conversation. Anything typed there, the model can be asked to repeat.
The names for these
The rest of this guide, and every specification, uses these terms. Each links to its entry in the glossary.
| In this lesson | Its name | Defined as |
|---|---|---|
| What a request carries as evidence | Credential | Whatever a request carries as evidence of who sent it and what it may do: an API key, a password, a token or a certificate. It is all the receiving service has to go on. |
| The agent’s own secret string | API key | A long-lived secret string that identifies the account it was issued to. It says nothing about which person a request is for, and it works for anyone who holds a copy. |
| Your agent, as the software asking for access | Client | In OAuth, the application requesting tokens. An agent, or the application hosting it, is the client. |
| The calendar service | Resource server | The API or service that accepts access tokens. An MCP server is a resource server. |
Go deeper
The same ground at full depth, when you want it. None of it is needed for the next lesson.
- What the API can verifyThe same comparison in full: a fourth check, and what refusing and revoking take.
- The rolesAll five parties in every diagram, with what each holds and verifies.