Signed URLs
A signed URL lets a browser or app read a private file, upload a file or load a resized image without holding your keys. Your server creates the URL, and it stops working after the expiry time.
When you need one
Section titled “When you need one”| Hostname | Signed URL | Expiry |
|---|---|---|
<space>.vault |
Always | Required |
<space>.upload |
Always | Required |
<space>.edge with image parameters |
Always | Not used |
<space>.edge without parameters |
Not needed | Not used |
URL format
Section titled “URL format”https://k3x9q2m7.vault.binedge.net/production/tickets/screenshot.png ?exp=1798765200&sig=<signature>exp is a Unix time in seconds (UTC). The URL works while the current time is before it. sig is an HMAC-SHA256 of the hostname role, your space name, the object key and the other parameters, encoded as base64url.
Sign on your server
Section titled “Sign on your server”Storage::disk('binedge') ->temporaryUrl('tickets/screenshot.png', now()->addMinutes(10));The disk adds your environment prefix (production/ or dev/) to the path, so the signed key is production/tickets/screenshot.png. Upload URLs come from temporaryUploadUrl() and resized image URLs from imageUrl(), see Uploads and Image resizing.
The string your server signs for the URL above:
BINEDGE-HMAC-SHA256vaultk3x9q2m7production/tickets/screenshot.pngexp=1798765200Sign it with HMAC-SHA256 and your signing key, then add the result to the URL as sig. The rules for each line follow below.
How the string is built
Section titled “How the string is built”Join these five lines with a line feed (0x0A), with no line feed after the last one:
BINEDGE-HMAC-SHA256<role><space><object key><canonical query><role>isvault,uploadoredge, the second label of the hostname.<object key>is the path without the leading/, decoded once, as UTF-8.%2Fbecomes/;+stays+.<canonical query>takes every parameter exceptsig, encodes each name and value as in RFC 3986 (A-Z a-z 0-9 - . _ ~stay as they are, every other byte becomes upper-case%XX), sorts them by encoded name, and joins them asname=valuewith&. With no parameters the line is empty.sigis the HMAC-SHA256 of the string with your signing key, encoded as base64url without=padding.
Which key signs which object
Section titled “Which key signs which object”The first part of the object key chooses the key, not the request:
| Key starts with | Signing key |
|---|---|
production/ or shared/ |
Your production signing key |
dev/ |
Your development signing key |
| Anything else | Rejected with key_scope_unknown |
Your development servers only hold the development key, so they cannot sign URLs under production/.
Check your implementation
Section titled “Check your implementation”These examples use the space k3x9q2m7 and the test key binedge-test-production-key. Your code should produce the same string to sign and the same sig.
A private file whose key has a space and Chinese characters:
BINEDGE-HMAC-SHA256vaultk3x9q2m7production/tickets/截图 1.pngexp=1798765200https://k3x9q2m7.vault.binedge.net/production/tickets/%E6%88%AA%E5%9B%BE%201.png?exp=1798765200&sig=OwicRpmPadfNbMpoA6zAMjfMR1pxvVyUY6b2vLQlCOkAn upload that accepts PNG and JPEG up to 10 MiB. The / and , in types are encoded in the string to sign:
BINEDGE-HMAC-SHA256uploadk3x9q2m7production/support-uploads/staging/7/b.jpgexp=1798765200&max_bytes=10485760&types=image%2Fpng%2Cimage%2Fjpeghttps://k3x9q2m7.upload.binedge.net/production/support-uploads/staging/7/b.jpg?exp=1798765200&max_bytes=10485760&types=image%2Fpng%2Cimage%2Fjpeg&sig=nppbmNIXVrRWiR4ZPWQe9MYUuJSDUNpQ1wGN2oLf1mAA resized public image. The parameters are sorted by name, and edge URLs have no exp:
BINEDGE-HMAC-SHA256edgek3x9q2m7production/groups/logo.pngcrop=smart&fit=cover&fmt=webp&h=144&q=75&w=144https://k3x9q2m7.edge.binedge.net/production/groups/logo.png?crop=smart&fit=cover&fmt=webp&h=144&q=75&w=144&sig=410RAzVg42KRbH5gEBlzbrYq5d7w-5avYm4J2EA9kroErrors
Section titled “Errors”| Reason | Meaning |
|---|---|
signature_missing |
The URL has no sig |
signature_invalid |
sig does not match the URL |
signature_expired |
The expiry time has passed |
key_scope_unknown |
The key does not start with production/, shared/ or dev/ |
All four return HTTP 403 with the reason in the error body. On edge and vault a visitor’s browser is then sent to the binedge.net error page, see Delivery URLs; upload returns the body as it is:
{"error":{"class":"permission_denied","message":"调用方无权访问该目标或能力。","retryable":false,"platform_code":null,"platform_message":null,"operation_id":null,"reason":"signature_expired"}}Branch on reason, not on message.