3.4 KiB
token-auth
(no submodules)
Purpose
Computes BunnyCDN Pull Zone Token Authentication query strings — ?token=<urlSafeBase64(sha256(key + path + expires))>&expires=<unix>, optionally with &token_path=<prefix> for path-scoped tokens. The signing scheme is BunnyCDN's documented Pull Zone protection: concatenate the per-Pull-Zone signing key with the path and expiry, SHA-256 hash, and URL-safe-base64 encode (no padding).
The adapter calls this from signUrl; consumers never invoke it directly unless they need to sign a URL outside the adapter's standard <pullZoneHostname>/<key> pattern.
Features
- SHA-256 via
crypto.subtle— runs in Node 18+, Bun, Deno, browsers, Workers. - URL-safe base64 output:
+→-,/→_, no=padding (matches BunnyCDN's verifier). - Optional
tokenPathquery parameter for prefix-scoped tokens. - Throws
STORAGE_CDN_BUNNYCDN.TOKEN_AUTH_KEY_MISSINGwhen the key is empty or missing. - Pure async function — no state, no side effects.
Usage: Basic
import { buildTokenAuthQuery } from "@suaveplan/storage-cdn-bunnycdn";
const query = await buildTokenAuthQuery({
tokenAuthKey: "per-zone-secret",
path: "/photos/a.jpg",
expires: Math.floor(Date.now() / 1000) + 60,
});
// query === "?token=<urlSafeBase64>&expires=<unix>"
Usage: Advanced
import { buildTokenAuthQuery } from "@suaveplan/storage-cdn-bunnycdn";
async function signedFolderUrl(hostname: string, folder: string, ttl: number): Promise<string> {
const expires = Math.floor(Date.now() / 1000) + ttl;
const tokenPath = `/${folder}/`;
const query = await buildTokenAuthQuery({
tokenAuthKey: process.env["BUNNY_TOKEN_KEY"]!,
path: tokenPath,
expires,
tokenPath,
});
return `https://${hostname}${tokenPath}${query}`;
}
API Reference
interface TokenAuthInput
{ tokenAuthKey, path, expires, tokenPath? }. path is the absolute path on the Pull Zone (with leading /). expires is Unix seconds. tokenPath enables prefix-scoped tokens (the token authorises every URL under the prefix until expiry).
buildTokenAuthQuery(input): Promise<string>
Returns the ?token=...&expires=... query string to append to the absolute edge URL. Throws STORAGE_CDN_BUNNYCDN.TOKEN_AUTH_KEY_MISSING on empty tokenAuthKey.
Implementation Notes
- BunnyCDN's signing scheme is SHA-256 (not HMAC). The secret is concatenated directly with
path + expiresand hashed; the URL-safe-base64 encoding makes the result safe for query-parameter inclusion. - Padding is stripped because BunnyCDN's verifier rejects tokens with
=characters; this is a documented quirk of their implementation. expiresis Unix seconds — BunnyCDN's standard everywhere. Passing milliseconds produces verifier rejections that read like "token expired" but are actually "token format wrong".- The function is async because
crypto.subtle.digestis Promise-returning. The underlying SHA-256 is fast (≪1ms). - The shipped tests assert determinism (same inputs → identical output), format correctness, and difference under varied inputs; byte-exact reference vectors are the responsibility of integration tests against a live BunnyCDN account.
btoais part of the universal runtime baseline (Node 18+, Bun, Deno, browsers, Workers); a Node-onlyBufferfallback is not needed.