AI agent API access: direct tokens or mediated actions?
AI agent API access needs more than narrow token scopes. Compare direct credentials with mediated actions for issues, deployments, support, and SSH.

An AI coding agent should not receive a general SaaS token just because it needs to call an API. Direct token delivery turns the agent process into a credential holder, with all the usual ways credentials escape: a verbose command, a child process, an uploaded diagnostic bundle, a tool result, or an instruction that tells the agent to print its configuration.
That does not mean every API call needs a ceremony. It means you should separate authority to perform an action from possession of the credential that authorizes it. Give an agent a constrained way to request useful work, keep the credential with the component that executes it, and make a human decision where the consequence deserves one.
This distinction gets blurred because a successful curl command looks harmless. The trouble begins after the agent can create a production deployment, close a customer ticket, alter an issue, or run a remote command. At that point, a token is not setup detail. It is operational authority with no judgment attached.
Direct token delivery makes the agent a credential boundary
When you put SAAS_TOKEN in an agent's environment, configuration file, tool definition, or prompt-accessible secret store, the agent can make authenticated requests without another component deciding whether each request belongs to the task. The token may have sensible scopes, but it still becomes available to every behavior of that process and often to programs it launches.
Developers often argue that the agent cannot "see" an environment variable. That claim does not survive ordinary tool use. An agent can ask a shell to inspect its environment, invoke a script that inherits it, run a test tool with debug logging, or write a configuration snapshot into a repository. The exact exposure path depends on the agent and its tools, which is why the safe assumption is simple: if the process can use a bearer token directly, it can usually cause the token to appear somewhere you did not plan.
A bearer token has another unpleasant property. The SaaS service cannot distinguish the intended agent from anyone who copied the string. RFC 6750, the OAuth 2.0 Bearer Token Usage specification, says bearer tokens require protection from disclosure in storage and transit because possession is sufficient to use them. That is not academic wording. Once an agent prints one into a build log, the service sees a valid caller, not a mistake.
Direct access also muddles accountability. Service audit logs may identify a bot account, but they rarely tell you which agent run formed the request, what instructions it received, which user started it, or whether a person approved the resulting effect. You get an API event after the fact, but not the decision trail that explains it.
A direct token can be tolerable in a disposable local sandbox when all of these are true:
- The token expires quickly and has only the minimum non-production scope.
- The target contains no customer, employee, or production data.
- The agent runs in an isolated environment you can discard.
- A human can revoke the credential without disrupting shared work.
Teams stretch this exception into routine practice because copying a token is fast. Speed is real, but so is the cleanup when the token lands in an artifact or an agent follows a malicious instruction embedded in an issue description.
Scopes limit permissions but do not control intent
OAuth scopes, API roles, and repository permissions answer "what may this identity do?" They do not answer "should this request happen now?" Those are different controls, and treating them as interchangeable leaves a large hole.
Consider an issue tracker token with permission to edit issues in one project. That scope may be correct for an agent assigned to triage bugs. A prompt injection in an imported issue can still tell the agent to close every open issue, change priorities, or post misleading comments. Each request fits the scope. Every request is still wrong.
The same issue appears with a deployment platform. A token scoped to one application does not know whether the agent should deploy the current commit, roll back a release, change an environment variable, or delete a preview environment. The service sees authorized API calls. Only your workflow can decide whether those calls match a task and an acceptable target.
The IETF OAuth 2.0 Security Best Current Practice recommends short-lived access tokens, sender-constrained tokens where possible, and narrower privileges to reduce bearer-token damage. Those are good practices. They reduce the useful life and reach of a copied credential. They do not add approval for a destructive but properly scoped action, and they do not explain an agent's intent.
Do not respond by making a giant catalog of rules that tries to predict every endpoint and argument. Teams build those catalogs, then spend months maintaining exceptions for new service APIs and unusual release procedures. A narrow action interface plus a human approval at the right moment usually survives contact with real work better than a policy language nobody can confidently read.
Issue trackers need write paths that preserve human judgment
Issue trackers look low risk until an agent starts making changes at volume. Closing an issue can suppress a customer report. Changing labels can break triage reports. Posting a comment can expose internal reasoning to external collaborators. Adding a user to a ticket can widen access to sensitive context.
Split the agent's work into observation and mutation. Let it retrieve issues, search labels, inspect linked pull requests, and draft a proposed update. Route the final mutation through an action that names the project, issue, fields changed, and comment body. A reviewer should see the actual content before the service receives it.
A request contract can make that boundary concrete. The agent should send structured intent, not assemble a credential-bearing command line.
{
"service": "issue-tracker",
"action": "update_issue",
"issue": "APP-184",
"changes": {
"labels_add": ["needs-reproduction"],
"comment": "I reproduced this on the current release and attached the failing test."
}
}
The executor should inject its own credential and return a bounded result:
{
"ok": true,
"issue": "APP-184",
"updated_fields": ["labels", "comment"],
"request_id": "service-request-id"
}
Do not return the raw Authorization header, a complete HTTP trace, or a debug object that includes secrets. This sounds obvious until someone enables verbose HTTP diagnostics during a difficult integration. Keep diagnostics behind a human-operated troubleshooting path, with redaction that you test rather than assume.
An agent can still make a poor judgment after a human approves a session. That is why destructive issue changes deserve a separate approval option. Session authorization answers whether this running program may use the integration at all. Per-call approval answers whether this specific mutation should occur. The distinction matters most when the agent can read untrusted text from tickets, documents, or pull request comments.
Deployment APIs carry consequences beyond the release button
A deployment API often exposes more than "deploy this version." It may alter environment variables, trigger builds, restart workloads, create domains, roll back versions, fetch logs, or delete resources. A broad deploy token becomes a convenient remote control for an agent that has already made a mistaken plan.
Use different action categories for deployment work. Reading a build status and retrieving a deployment's public metadata are usually routine. Promoting an artifact to production, rolling back a release, changing a secret reference, and deleting an environment have different consequences. Do not group them behind a single approval that says "deployment access."
A sensible request asks for an immutable artifact reference and an explicit target. Reject vague inputs such as "latest" when the service can resolve a commit, image digest, or build identifier. Mutable labels create a time gap between approval and execution: the reviewer approves one thing, while the action runs another.
{
"service": "deployment-platform",
"action": "promote_release",
"application": "billing-api",
"environment": "production",
"artifact": {
"git_commit": "8cf4f3a",
"build_id": "build-4921"
},
"reason": "Fixes the confirmed invoice retry failure"
}
The executor should check that the approved identifiers match the request it sends. It should also record the service response identifier and the target environment. Recording only "deploy succeeded" gives you very little to work with at 2 a.m. when somebody asks which artifact moved and who authorized it.
Do not make the agent scrape a web dashboard to avoid API design. Browser automation hides details from review, breaks without warning, and can click through a stale page state. If the platform offers an API, use a narrow mediated action over the API. If it offers only a dashboard, accept that some operations remain human work until you can build a dependable connector.
Customer support tools require data minimization before automation
Customer support systems combine operational actions with personal data. A ticket can include account details, contact information, attachments, order history, logs, and emotionally charged messages. Direct agent access raises two questions: can the agent read material it does not need, and can it send a harmful reply under your company's name?
Do not solve this by sending full ticket transcripts to an agent as the default. Fetch only the fields needed for the task. If the agent needs to classify a ticket, it may need the subject, a redacted body, and product area. It probably does not need every prior internal note, billing record, or attachment.
Write actions need tighter review than classification. A useful pattern is draft first, send second. The agent creates a response proposal with references to the ticket and any internal source it used. A person checks tone, factual claims, account-specific details, and whether the reply accidentally reveals internal notes. Only then should an executor post the message.
Closing, merging, or reassigning tickets deserve explicit action semantics as well. "Resolve ticket" is too vague if it silently sends a closure email, changes a service-level agreement clock, or deletes a draft. Your request schema should identify the side effect the support service will perform.
This is where a broad service account is especially tempting. It avoids permissions friction, and it lets the agent handle any queue. It also means one flawed instruction can cross account boundaries. Assign service identities to queues or teams where the provider permits it, then limit the mediated action interface to the operations that team actually needs.
SSH is execution authority, not an API credential with different syntax
SSH deserves separate treatment because a private key can lead to a shell, file transfer, port forwarding, and access to tools that have their own credentials. A deployment API may offer a finite set of operations. A remote shell can compose new operations on the spot.
Giving a coding agent an SSH private key creates two risks at once. The key may leak, and the agent can generate arbitrary remote commands. Restricting the account helps, but a restricted account with access to deployment scripts, cloud CLI credentials, or production configuration can still do much more than the original task implied.
Use a mediator that holds the private key and receives a requested host, command, and arguments. Make the action record the resolved host and the exact command after argument handling. Do not approve a shell string that the agent can later reinterpret through nested quotes, command substitution, or a remote script fetched from an untrusted branch.
For sensitive hosts, prefer fixed remote operations over general shell access. A command such as release-status --service billing-api is easier to review than bash -lc '...'. If you must allow a general command, display it exactly as it will execute and require approval per call. Treat sudo, package installation, secret file reads, shell redirection, and outbound copy commands as higher-risk cases, not as ordinary maintenance.
SSH host verification matters too. The client must verify the server host key against a managed known-hosts entry. Accepting a new host fingerprint automatically lets a network or DNS mistake become a credential-use event. That defeats the purpose of carefully hiding the private key.
Mediated actions contain credentials and create a decision point
A mediated action system keeps the SaaS token or SSH private key inside an executor and gives the agent an interface for asking it to perform defined work. The executor attaches credentials, makes the request, and returns the result. The agent never receives a secret, including a placeholder that it could accidentally substitute into a command.
This changes the failure mode. A direct-access agent that accepts a malicious instruction can both decide on and execute an action with a reusable credential. A mediated agent can still request a bad action, because no security control makes language-model judgment perfect. But the executor can identify the caller, require a person to approve the call, keep credentials unavailable to the agent, and record the request and result.
Sallyport uses this model for HTTP API calls and SSH commands: an MCP-capable agent connects through sp mcp, while the macOS app holds API and SSH credentials in its encrypted vault and executes actions itself. Its vault gate denies every action while locked, which is the correct behavior when the person responsible is away from the machine.
Do not confuse a mediator with a man-in-the-middle proxy. A proxy observes or relays general traffic. An action gateway receives a specific action request, applies its authorization controls, uses a credential it retains, and returns an outcome. That tighter shape is useful because it supplies an approval point and audit record instead of trying to interpret all traffic after the agent has already formed it.
The best mediated interfaces are intentionally boring. They expose a small number of understandable verbs, accept structured parameters, reject ambiguous targets, and report enough information to verify the effect. A clever universal request endpoint that accepts arbitrary URLs, headers, and bodies can quietly recreate direct access with more steps.
Approval design fails when people cannot judge the request
An approval prompt has to help a person decide, not simply interrupt them. "Agent requests access to support tool" asks the reviewer to bless an unknown future. "Post this reply to ticket 4821 as the support team" gives the reviewer a concrete action to inspect.
For a first call from a new agent process, show the process identity and code-signing authority. Process identity is not decoration. On a development machine, several terminals, extensions, and helper programs can request the same integration. A reviewer should know which signed program is asking before granting a session.
Then choose authorization at the right level:
- Use a session approval for low-impact work that needs repeated reads or routine calls during one agent run.
- Use a per-call approval for external messages, state changes, deployments, remote commands, and actions with irreversible effects.
- Lock the credential store when you are away, so every action fails rather than waiting for an unattended approval.
- Revoke the current session when the task changes, the agent behaves oddly, or you no longer recognize the process.
Approval fatigue is a design failure. If a person must approve every harmless retrieval, they will train themselves to click through. If one approval grants an agent a whole afternoon of production mutations, the interface has hidden too much authority behind convenience. Split action types according to consequence, then make ordinary activity quiet and consequential activity specific.
Avoid approval text that repeats the agent's own vague description. The action layer already has structured fields. Use them. Display the service, authenticated account or role, target project or host, operation, and any human-facing content that will leave the organization. Redact credentials and private fields that the reviewer does not need.
Logs must connect an agent run to each external effect
Service-provider logs alone are insufficient for agent work because they begin at the API boundary. Agent transcripts alone are insufficient because they can omit the actual request or be edited. You need both a run-level record and a call-level record that share a reliable connection.
A run-level journal should identify the agent process, its session start and end, the approval that allowed it, and a way to revoke it immediately. A call-level journal should record the action request, authorization outcome, execution result, target, and service request identifier when one exists. Keep sensitive request bodies out of routine displays when they contain customer content, but retain enough protected evidence to investigate an incident.
Tamper evidence matters if the logs may answer a dispute. A plain local text file can show a useful history, but a user or compromised process can rewrite it. A hash chain makes each record depend on the previous record, so later edits break verification. That does not make the log infallible. It makes undetected rewriting harder and gives an investigator a testable integrity property.
Sallyport projects its Sessions and Activity journals from a write-blind encrypted, hash-chained audit log. You can verify the ciphertext chain offline with sp audit verify, without the vault key. A healthy verification should have an output shape like this:
Audit chain: valid
Records checked: 184
First sequence: 1
Last sequence: 184
If verification reports a broken sequence or hash mismatch, preserve the files and investigate before relying on the journal. Do not "repair" a suspect log by deleting the bad tail. That may remove the only evidence of when and how the record changed.
A direct-token migration should start with the riskiest credential
Do not try to redesign every integration in one week. Begin with the credential whose misuse would create the hardest recovery: production deployment authority, broad customer support access, or an SSH key that reaches shared systems. The migration should remove usable secrets from the agent before it attempts to perfect every workflow.
Use this sequence for each integration:
- Inventory where the agent obtains the credential today. Include environment variables, repository files, CI secrets, shell profiles, tool configuration, and copied prompts.
- List the operations the agent genuinely performs, then separate reads, drafts, mutations, and remote execution. Most direct tokens allow far more than this list.
- Create structured action requests for the needed operations. Bind every write to a named target and every deployment to an immutable artifact reference.
- Move the credential into an executor that the agent cannot read. Rotate the old credential after you prove the new path works.
- Test failure deliberately: lock the vault, deny an approval, revoke a session, submit an invalid target, and run audit verification. A happy-path demo proves almost nothing.
The rotation step catches a mistake teams make constantly: they add a mediator but leave the original token in the agent's environment "for fallback." That leaves two routes to the same authority, and the less controlled one will eventually get used. Remove the fallback. If the mediated path cannot support a required operation yet, document the temporary exception, limit its scope and lifetime, and put a named person on its removal.
Direct token delivery is easy because it hands the hard decision to a string in a process environment. For throwaway sandboxes, that trade may be reasonable. For services that affect customers, deployments, or shared infrastructure, keep credentials out of the agent and make the action itself visible before it happens.
FAQ
Can I give an AI coding agent a personal access token?
Sometimes, but only when the token has a narrow scope, a short lifetime, a clear owner, and no consequence beyond the agent's assigned task. A broad personal token copied into an agent environment fails that test. Treat it as an exception that needs a written expiry date, not as the default setup.
Is read-only API access safe for an AI agent?
Read-only access reduces the damage from a bad request, but it still exposes customer data, source code metadata, incident notes, and internal structure. It also leaves a token in a place where prompts, logs, or subprocesses may expose it. Read-only is a permission level, not a credential-handling method.
Does OAuth make direct agent access safe?
No. A human-approved OAuth grant says a user authorized an application for a period of time. It does not prove that each later request matches a task, nor does it protect a bearer token after an agent process receives it. Use OAuth for delegated identity where it fits, then keep the resulting authority out of the agent process if you can.
Should an AI agent use a dedicated service account?
Use a separate identity when the service supports it and when you can give that identity a narrowly defined role. Do not mistake a bot account for containment if the agent still receives a permanent credential. The bot identity limits blast radius; mediated execution controls credential exposure and records each action.
What should an approval prompt show before an agent calls an API?
An approval should identify the calling process and state the action in terms a human can judge: target service, account, endpoint or command, and material effect. Approving a vague request such as "allow tool access" trains people to approve blind. Session approval and per-call approval solve different problems, so use both where the risk warrants it.
Are environment variables an acceptable place for agent API tokens?
No, not if the machine or agent workspace has access to the file that contains it. Environment variables often spread into child processes, diagnostics, crash reports, and debug output. A secret manager helps with storage, but direct delivery still gives the agent process the usable secret.
How does mediated API access limit prompt injection damage?
Prompt injection can persuade an agent to make a legitimate-looking tool call for an illegitimate purpose. A mediating action layer cannot make the model understand intent perfectly, but it can keep credentials hidden, ask for consent at the point of impact, limit available operations, and leave evidence for review. Those controls turn a silent mistake into an observable event.
What should I do if an agent reveals an API token?
Treat the token as exposed and revoke or rotate it immediately. Then inspect service audit records, agent session records, shell history, CI logs, local logs, and any artifacts the agent could write. Do not wait for proof that someone used it, because bearer credentials provide no way to distinguish a legitimate holder from a copied token.
Why is SSH access riskier than a SaaS API token for agents?
SSH adds host targeting, remote shell execution, port forwarding, file transfer, and command composition. A deployment token may call a small API; an SSH credential can often reach an operating system with many paths to the same outcome. Keep the private key out of the agent and require clear review for commands with production effects.
When is an action gateway worth using for AI agents?
It is worth the setup when an agent can touch production, customer records, billing, deployments, or shared infrastructure. For a disposable local sandbox with an expiring, low-scope credential, direct access may be faster and acceptable. The deciding factor is consequence, not whether the agent calls itself autonomous.