Function scopes
The seven scopes a deployed Function's token carries, what each one permits, and what a Function deliberately cannot do.
A Function's credential is granted the same seven scopes on every deployment, and the set is not configurable. Anything outside it needs a key you create yourself.
| Scope | Permits |
|---|---|
network:storage_objects:read | List objects, read object and upload session metadata, list the trash, mint an object access URL |
network:storage_objects:write | Create an upload session, restore an object from the trash |
network:storage_objects:delete | Move an object to the trash, purge it, empty the trash |
network:sticky_sessions:write | Mint a sticky session URL that routes a client back to the Function holding its state |
network:runtime_cache:read | Read entries from the deployment's private runtime cache |
network:runtime_cache:write | Write entries to that cache |
network:runtime_cache:revalidate | Invalidate tags in that cache |
The three runtime cache scopes exist for the framework adapters, such as the Next.js cache handler a build installs for you. Application code rarely touches that surface directly.
What a Function cannot do
No platform: scope is granted at all, and none of the network: scopes covering applications, deployments, environment variables, storage buckets, S3 credentials, request logs, the AI Gateway, or image optimization. A Function cannot create a bucket, trigger a deployment, read its own request logs, or send an AI Gateway completion. It cannot read environment variables through the API either, though it does not need to: the ones that apply to it are already in its environment.
It also cannot mint a key for itself. platform:api_keys:write is not in the set, and no minted key may ever carry a platform:api_keys: scope, so there is no path from a leaked Function credential to a broader one.
When your code genuinely needs one of those operations, create an application-scoped key with exactly that scope, as described in API keys, and pass its id and secret to the client:
import { GigadriveClient } from '@gigadrive/sdk';
const clientId = process.env.AI_CLIENT_ID;
const clientSecret = process.env.AI_CLIENT_SECRET;
if (!clientId || !clientSecret) {
throw new Error('AI Gateway credentials are missing');
}
// Explicit options beat the injected environment, so this client acts as the key
// rather than as the Function.
const gateway = new GigadriveClient({ clientId, clientSecret });
const answer = await gateway.aiGateway.chatCompletions({
model: 'openai/gpt-4o',
messages: [{ role: 'user', content: 'Summarise this ticket in one sentence.' }],
});
console.log(answer.choices[0].message.content);Scope is only half the check
A scope says what kind of call is allowed. It says nothing about which application. Every request also resolves the actor behind the token, and a Function's token resolves to that Function, bound to one deployment and one application.
A call that names another application is refused with 403 Access denied: You do not have permission to access this application. An id that resolves to nothing answers 404, and so does a malformed one. Two endpoints narrow this further: minting a sticky session URL answers 403 for any credential that is not a deployed Function, and the runtime cache answers 403 The workload may only access its own deployment cache outside its own deployment.
Why the set is small
Every scope in the table is something a request handler does while serving traffic: read a file, store an upload, pin a WebSocket, cache a render. Creating applications, editing environment variables, and triggering deployments are management operations. We keep those on credentials that a person or a CI job owns, because those have an expiry, an owner, and an audit trail, and a Function has none of the three.
A fully compromised Function reaches the storage objects of its own application, its own runtime cache, and sticky URLs for its own deployment. That is the ceiling. The complete list of scopes the API enforces is in Scopes.
