Skip to content

Temporary credentials

Temporary credentials are short-lived, scoped S3 credentials derived from an existing R2 API token. They authenticate with AWS Signature Version 4, the same as a long-lived token, but include a session token and expire automatically. The session token is sent with every request via the X-Amz-Security-Token header; all S3-compatible clients expose this as a standard session token credential field.

Use temporary credentials to delegate access without issuing a long-lived token. For example, granting a mobile client read access to a single prefix for 15 minutes, or issuing per-request upload credentials scoped to one object.

Choosing an approach

R2 supports two patterns for time-limited access. They overlap but have different trade-offs:

PatternGrantsGood for
Temporary credentials (this page)Multiple S3 operations, scoped to a bucket and a set of permitted operations, and optionally to specific pathsCallers that use a standard S3 client or SDK to perform multiple operations in a scoped session
Presigned URLsA single S3 operation on a single objectGranting direct HTTP access to a single object without an S3 client, such as a browser upload or a shareable download link

Generate temporary credentials

Via the Temporary Credentials API

The Temporary Credentials API accepts a parent API token, the bucket name, and optional scoping parameters, and returns a new access key ID, secret access key, and session token. Cloudflare signs the session token on your behalf.

Use this method when you want Cloudflare to manage the signing flow for you.

For a runnable walkthrough, refer to Authenticate against R2 with temporary credentials.

Locally (client-side signing)

You can also generate temporary credentials locally by signing a JWT with your parent API token's secret access key and using it as the session token.

Use this method when:

  • You are issuing many short-lived credentials and want to avoid per-mint API latency.
  • You need to mint credentials in an environment that cannot reach the Cloudflare API.
  • You want to scope credentials by S3 action (see Scope by action), which is currently supported via local signing only.

Signing happens in three steps:

  1. Build a JWT payload that identifies the bucket and the scope of access.
  2. Sign the JWT with HS256 using your parent secret access key.
  3. Derive the temporary secret access key by taking the SHA-256 hex digest of the signed JWT. Encode the session token as base64("jwt/" + <signed-jwt>).

The parent access key ID is reused as the temporary access key ID.

A complete, runnable example is available in Authenticate against R2 with temporary credentials.

Scope of a credential

Every temporary credential is bound to a single bucket and a set of permitted operations. You can optionally restrict the credential further to specific paths within the bucket.

A temporary credential cannot exceed the permissions of its parent token.

Bucket

A temporary credential is bound to exactly one bucket, identified by name. Cross-bucket access is not supported within a single credential.

Permitted operations

Specify permitted operations using scope (passed as permission to the API) or actions. You must provide at least one.

Scope

scope is a preset category of operations. Refer to Permissions for full definitions.

ScopeAllows
object-read-onlyRead and list objects in the bucket.
object-read-writeRead, write, and list objects in the bucket.
admin-read-onlyRead and list objects, view bucket configuration, and read from the data catalog.
admin-read-writeRead, write, and list objects, edit bucket configuration, and read and write to the data catalog.

Actions

actions is an explicit list of permitted S3 operations.

For example, actions: ["GetObject", "HeadObject"] grants read of individual objects but denies ListObjectsV2, even though the broader object-read-only scope would allow listing.

Valid actions:

CategoryActions
ReadHeadObject, GetObject, GetBucketLocation, ListObjectsV1, ListObjectsV2, ListMultipartUploads, ListParts
WritePutObject, DeleteObject, DeleteObjects, CopyObject
MultipartCreateMultipartUpload, UploadPart, UploadPartCopy, AbortMultipartUpload, CompleteMultipartUpload

Paths

Restrict access to specific prefixes or objects within the bucket. Omit these fields to grant access to the entire bucket, subject to the permitted operations.

Temporary Credentials API: pass prefixes and objects as top-level fields on the request body.

JSONC
{
"prefixes": ["uploads/user-123/"],
"objects": ["shared/manifest.json"]
}

Local signing: set paths.prefixPaths and paths.objectPaths on the JWT payload.

JSONC
{
"paths": {
"prefixPaths": ["uploads/user-123/"],
"objectPaths": ["shared/manifest.json"]
}
}
  • prefixes / prefixPaths: keys starting with any listed prefix.
  • objects / objectPaths: exact object keys.

Using temporary credentials

Any S3-compatible client that supports session tokens will accept R2 temporary credentials. Pass all three values (access key ID, secret access key, session token) using the client's standard credential fields.

TypeScript
import { AwsClient } from "aws4fetch";
const R2_URL = `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`;
const client = new AwsClient({
accessKeyId: ACCESS_KEY_ID,
secretAccessKey: SECRET_ACCESS_KEY,
sessionToken: SESSION_TOKEN,
service: "s3",
});
const response = await client.fetch(`${R2_URL}/my-bucket/image.png`);

Security considerations

Treat temporary credentials as bearer tokens. Anyone in possession of all three values can perform the allowed operations until the credential expires.

  • Scope as narrowly as possible. Set paths and permission scope so the credential can only do what the caller needs.
  • Use short TTLs. Set ttlSeconds to the shortest value that fits your use case. A credential that lives for 15 minutes has a smaller blast radius than one that lives for a day.
  • A temporary credential cannot exceed its parent. If you revoke the parent API token, all temporary credentials derived from it stop working immediately.
  • Never ship your parent secret access key to a client. Local signing must happen in a trusted environment (such as your backend or a Worker).