cdnzero
Get started free →
Features

Signed URLs

Grant temporary, authenticated access to private files — without exposing your API key.


The pattern

A signed URL embeds a cryptographic signature and expiry time. You generate it server-side with your Secret Key, then hand it to the client. The CDN validates the signature on every request and rejects expired or tampered URLs.

1
2
3

Client requests a file from your app

Your server checks auth — is the user allowed to see this file?

Your server calls CDNZero's create-link API

Returns a time-limited presigned_url (e.g. TTL = 15 min)

Your server redirects the client to the presigned URL

The CDN serves the file directly. Your API key never leaves the server.

Generating a signed URL

bash
curl -X POST https://api.cdnzero.com/collections/create-link \
  -H "Authorization: Bearer YOUR_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file_id": "file_abc123",
    "file_type": "image",
    "expiry": 900
  }'
Response
{
  "file_id": "file_abc123",
  "file_type": "image",
  "expiry": 900,
  "presigned_url": "https://cdn.cdnzero.com/files/abc123.png?X-Sig=...&X-Expires=..."
}

Parameters

ParamTypeDefaultDescription
file_idstringrequiredID of the private file
file_typestringrequiredimage, video, or document
expirynumber3600TTL in seconds (max 86400 = 24 h)

Next.js example

app/api/media/route.ts
import { NextRequest, NextResponse } from 'next/server';

export async function GET(req: NextRequest) {
  const fileId = req.nextUrl.searchParams.get('id')!;

  const res = await fetch('https://api.cdnzero.com/collections/create-link', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CDNZERO_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ file_id: fileId, file_type: 'image', expiry: 900 }),
  });

  const { presigned_url } = await res.json();
  return NextResponse.redirect(presigned_url);
}
Use signed URLs for anything user-specific: profile photos, invoices, private uploads. Keep the TTL short (5–15 minutes) for sensitive content.