← Cloudflare R2 / r2 / examples
Аутентификация в R2 с помощью временных учётных данных
В следующих примерах показано, как генерировать R2 временные учётные данные как через Temporary Credentials API, так и с помощью локального клиентского подписания, а также как использовать полученные учётные данные с S3-клиентом.
Предварительные требования
- Родительский R2 API-токен как минимум с теми разрешениями, которые вы планируете делегировать. Никогда не передавайте родительские учётные данные клиенту.
- Ваш Cloudflare ID аккаунта.
- Клиент S3, поддерживающий токены сессии. В примерах ниже используется aws4fetch ↗.
Генерация через Temporary Credentials API
Вызовите Temporary Credentials API с доверенного сервера, а затем используйте полученные учётные данные с любым S3-клиентом.
curl https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/r2/temp-access-credentials \
--header "Authorization: Bearer <PARENT_API_TOKEN>" \
--header "Content-Type: application/json" \
--data '{
"bucket": "my-bucket",
"parentAccessKeyId": "<PARENT_ACCESS_KEY_ID>",
"permission": "object-read-only",
"ttlSeconds": 900,
"objects": ["reports/2026-q1.pdf"]
}'Ответ оборачивает учётные данные в result объект:
{
"result": {
"accessKeyId": "<accessKeyId>",
"secretAccessKey": "<secretAccessKey>",
"sessionToken": "<sessionToken>"
},
"errors": [],
"messages": [],
"success": true
}Локальная генерация (подпись на стороне клиента)
В этом примере используется jose ↗ чтобы подписать JWT и aws4fetch ↗ чтобы выдавать подписанные запросы.
npm i jose aws4fetchСледующая вспомогательная функция подписывает JWT с помощью вашего родительского секретного ключа доступа и получает временный секретный ключ доступа и токен сессии:
import { SignJWT } from "jose";
type R2Scope =
| "object-read-only"
| "object-read-write"
| "admin-read-only"
| "admin-read-write";
export interface TempCredentialOptions {
scope: R2Scope;
// Optional: narrow the credential to specific S3 operations.
actions?: string[];
// Time-to-live in seconds. Defaults to 1 hour.
ttlSeconds?: number;
// Optional: restrict access to specific prefixes or objects.
paths?: { prefixPaths?: string[]; objectPaths?: string[] };
}
export async function createTempCredentials(
endpoint: string,
accountId: string,
parentAccessKeyId: string,
parentSecretAccessKey: string,
bucket: string,
opts: TempCredentialOptions,
): Promise<{
accessKeyId: string;
secretAccessKey: string;
sessionToken: string;
}> {
const ttl = opts.ttlSeconds ?? 3600;
const claims: Record<string, unknown> = {
bucket,
scope: opts.scope,
};
if (opts.actions !== undefined && opts.actions.length > 0) {
claims.actions = opts.actions;
}
if (opts.paths !== undefined) {
claims.paths = {
prefixPaths: opts.paths.prefixPaths ?? [],
objectPaths: opts.paths.objectPaths ?? [],
};
}
// Sign the JWT with the parent secret access key. R2 validates this signature.
const jwt = await new SignJWT(claims)
.setProtectedHeader({ alg: "HS256", typ: "JWT" })
.setSubject(accountId)
.setIssuer(parentAccessKeyId)
.setAudience(new URL(endpoint).host)
.setIssuedAt()
.setExpirationTime(`${ttl}s`)
.sign(new TextEncoder().encode(parentSecretAccessKey));
// The temporary secret access key is the SHA-256 hex digest of the signed JWT.
const digest = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(jwt),
);
const secretAccessKey = Array.from(new Uint8Array(digest))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
return {
// Reuse the parent access key ID as the temporary access key ID.
accessKeyId: parentAccessKeyId,
secretAccessKey,
// The session token is base64("jwt/" + signed JWT).
sessionToken: btoa(`jwt/${jwt}`),
};
}В следующем примере возвращаются учётные данные, действительные в течение 15 минут и позволяющие только GetObject и HeadObject в разделе data/ префикс:
import { createTempCredentials } from "./temp-credentials";
const R2_URL = `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`;
const creds = await createTempCredentials(
R2_URL,
ACCOUNT_ID,
PARENT_ACCESS_KEY_ID,
PARENT_SECRET_ACCESS_KEY,
"my-bucket",
{
scope: "object-read-only",
actions: ["GetObject", "HeadObject"],
ttlSeconds: 900,
paths: { prefixPaths: ["data/"] },
},
);Использование учётных данных
После получения временных учётных данных использование не зависит от способа их создания. Передайте все три значения S3-клиенту и отправляйте запросы. В следующем примере используются учётные данные, ограниченные data/ префикс, чтобы продемонстрировать один разрешенный и один отклоненный запрос:
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",
});
// Allowed: object under the data/ prefix.
const ok = await client.fetch(`${R2_URL}/my-bucket/data/file.bin`);
console.log(ok.status); // 200
// Rejected with 403 AccessDenied because the object is outside the data/ prefix.
const denied = await client.fetch(`${R2_URL}/my-bucket/other/file.bin`);
console.log(denied.status); // 403Дополнительные материалы
- Временные учётные данные: описание концепции и модели области действия.
- R2 API-токены: создание родительского токена.
- Коды ошибок: справочник по ошибкам аутентификации.