Documentation
Learn how to use presigned URLs
TL;DR
Presign is an open-source service that generates secure, time-limited presigned URLs for any HTTP API. It lets you share API access with teammates, scripts, or applications without exposing your API keys. Keys are AES-256 encrypted at rest, and URLs use HMAC-SHA256 signatures.
What is a Presigned URL?
A presigned URL is a temporary, secure link that allows access to an API without exposing the underlying API key. It includes built-in access controls like rate limiting, path restrictions, and expiration.
How to Use
Create a Connection
Add your API provider and store your API key. You'll receive a Connection ID and a Signing Secret.
Sign URLs in your code
Use HMAC-SHA256 to sign presigned URLs in your own infrastructure. You control expiration, allowed methods, and paths.
Use the presigned URL
Share the URL with clients or use it directly. presign.click verifies the signature and proxies the request to your API.
URL Format
https://presign.click/api/proxy/{connectionId}/{path}?X-Presign-Expires={unix}&X-Presign-Methods={methods}&X-Presign-Paths={paths}&X-Presign-Signature={hmac}connectionId -- Your connection ID (from the Connections page)
path -- API path to proxy (e.g., v1/chat/completions)
X-Presign-Expires -- Unix timestamp (seconds). Use 0 for no expiration.
X-Presign-Methods -- Comma-separated HTTP methods, sorted alphabetically (e.g., GET,POST). Use * for all.
X-Presign-Paths -- Comma-separated path patterns, sorted alphabetically (e.g., v1/chat/*,v1/models). Use * for all.
X-Presign-Signature -- Hex-encoded HMAC-SHA256 signature
Signing Algorithm
Build a canonical string and sign it with HMAC-SHA256 using your connection's signing secret:
Canonical String:
PRESIGN-HMAC-SHA256
{connectionId}
{expiresUnix}
{sortedMethods}
{sortedPaths}
Signature = HMAC-SHA256(signingSecret, canonicalString)
-> hex-encoded Lines are joined by \n. Methods and paths must be sorted alphabetically and comma-separated.
API Reference
Response Codes
Code Examples
JavaScript / Node.js
import crypto from 'node:crypto'
const CONNECTION_ID = 'conn_your_id'
const SIGNING_SECRET = 'sk_your_secret'
function createPresignedUrl({ path, methods, paths, expiresIn }) {
const expires = expiresIn
? Math.floor(Date.now() / 1000) + expiresIn
: 0
const sortedMethods = [...methods].sort().join(',')
const sortedPaths = [...paths].sort().join(',')
const canonical = [
'PRESIGN-HMAC-SHA256',
CONNECTION_ID,
expires,
sortedMethods,
sortedPaths,
].join('\n')
const signature = crypto
.createHmac('sha256', SIGNING_SECRET)
.update(canonical)
.digest('hex')
const params = new URLSearchParams({
'X-Presign-Expires': String(expires),
'X-Presign-Methods': sortedMethods,
'X-Presign-Paths': sortedPaths,
'X-Presign-Signature': signature,
})
return `https://presign.click/api/proxy/${CONNECTION_ID}/${path}?${params}`
}
// Create a URL that allows POST to chat completions, expires in 1 hour
const url = createPresignedUrl({
path: 'v1/chat/completions',
methods: ['POST'],
paths: ['v1/chat/*'],
expiresIn: 3600,
})
// Use it
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
})
})Python
import hmac, hashlib, time, requests
from urllib.parse import urlencode
CONNECTION_ID = 'conn_your_id'
SIGNING_SECRET = 'sk_your_secret'
def create_presigned_url(path, methods, paths, expires_in=None):
expires = int(time.time()) + expires_in if expires_in else 0
sorted_methods = ','.join(sorted(methods))
sorted_paths = ','.join(sorted(paths))
canonical = '\n'.join([
'PRESIGN-HMAC-SHA256',
CONNECTION_ID,
str(expires),
sorted_methods,
sorted_paths,
])
signature = hmac.new(
SIGNING_SECRET.encode(),
canonical.encode(),
hashlib.sha256
).hexdigest()
params = urlencode({
'X-Presign-Expires': expires,
'X-Presign-Methods': sorted_methods,
'X-Presign-Paths': sorted_paths,
'X-Presign-Signature': signature,
})
return f'https://presign.click/api/proxy/{CONNECTION_ID}/{path}?{params}'
# Create a URL that expires in 1 hour
url = create_presigned_url(
path='v1/chat/completions',
methods=['POST'],
paths=['v1/chat/*'],
expires_in=3600,
)
# Use it
response = requests.post(url, json={
'model': 'gpt-4',
'messages': [{'role': 'user', 'content': 'Hello'}]
})cURL (with bash signing)
#!/bin/bash
CONN_ID="conn_your_id"
SECRET="sk_your_secret"
EXPIRES=$(($(date +%s) + 3600)) # 1 hour
METHODS="POST"
PATHS="v1/chat/*"
CANONICAL="PRESIGN-HMAC-SHA256
${CONN_ID}
${EXPIRES}
${METHODS}
${PATHS}"
SIGNATURE=$(echo -n "$CANONICAL" | openssl dgst -sha256 -hmac "$SECRET" -hex | cut -d' ' -f2)
curl "https://presign.click/api/proxy/${CONN_ID}/v1/chat/completions?\
X-Presign-Expires=${EXPIRES}&\
X-Presign-Methods=${METHODS}&\
X-Presign-Paths=${PATHS}&\
X-Presign-Signature=${SIGNATURE}" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4", "messages": [{"role": "user", "content": "Hello"}]}'Frequently Asked Questions
What is Presign?
Presign is an open-source service that generates secure, time-limited presigned URLs for any HTTP API. It lets you share API access with teammates, scripts, or applications without exposing your API keys. Keys are AES-256 encrypted at rest, and URLs use HMAC-SHA256 signatures.
How does Presign work?
You store your API key in Presign (encrypted with AES-256), then generate a presigned URL with specific permissions: allowed HTTP methods, URL path patterns, and an expiration time. The URL is signed with HMAC-SHA256 using your signing secret. When someone uses the URL, Presign verifies the signature and proxies the request to the API.
Is Presign free?
Yes. Presign offers a free tier with 3 API connections and 1,000 requests per month. No credit card required. Pro and Enterprise plans are available for teams needing more capacity.
What APIs does Presign support?
Presign works with any HTTP API. The API Store includes preconfigured providers like OpenAI, Anthropic, Groq, and more. You can also add any custom API by providing its base URL.
Is Presign secure?
Yes. API keys are encrypted with AES-256 at rest and never leave the server. Presigned URLs use HMAC-SHA256 signatures and can be restricted by HTTP method, path pattern, and expiration time. The service runs on Cloudflare Workers at the edge.
How is Presign different from API gateways?
Unlike traditional API gateways, Presign focuses specifically on presigned URL generation. URLs are self-contained with their permissions encoded in the signature — no session state, no token refresh, no SDK required. Recipients just use a plain URL.