This page provides an overview of Signed URLs, which is a mechanism for query string authentication for buckets and objects. Signed URLs provide a way to give time-limited read or write access to anyone in possession of the URL, regardless of whether they have a Google account. To learn how to create a Signed URL, read Creating Signed URLs with gsutil and Creating Signed URLs with a Program. To learn about other ways of controlling access to buckets and objects, read Overview of Access Control.
When should you use a signed URL?
In some scenarios, you might not want to require your users to have a Google account in order to access Cloud Storage, but you still want to control access using your application-specific logic. The typical way to address this use case is to provide a signed URL to a user, which gives the user read, write, or delete access to that resource for a limited time. Anyone who knows the URL can access the resource until the URL expires. You specify the expiration time in the query string to be signed.
Using signed URLs with resumable uploads
If your users are only uploading resources (writing) to an access-controlled
bucket, you can use the resumable uploads functionality of Cloud Storage to
require only one signed URL. This signed URL is part of the initial
POST request, during which no data is actually uploaded. A session URI is
returned from the initial
POST request which can then be used in
PUT requests to upload data. Since the session URI is, in effect,
an authentication token, the
PUT requests do not need to be signed. The
POST request can be made by the server, avoiding the
need for clients to use signing URLs or a Google account.
Resumable uploads are pinned in the region they start in. For example, if you
create a resumable upload URL in the US and give it to a client in Asia, the
upload still goes through the US. Performing a resumable upload in a region
where it wasn't initiated can cause slow uploads. To avoid this, you can have
POST request constructed and signed by the server, but then give
the signed URL to the client so that the upload is initiated from their
location. Once initiated, the client can use the resulting session URI
normally to make
PUT requests that do not need to be signed.
If you use Compute Engine instances with processes that
POST to Cloud Storage to initiate a
resumable upload, then you should use Compute Engine instances in the same locations as your
Cloud Storage buckets. You can then use a geo IP service to pick the Compute Engine region to which you
route customer requests, which helps keep traffic localized to a geo-region.
Components of the string that requires signing
When creating a signed URL using a program, your program constructs a string that will be signed. This string should be defined in your program as:
StringToSign = HTTP_Verb + "\n" + Content_MD5 + "\n" + Content_Type + "\n" + Expiration + "\n" + Canonicalized_Extension_Headers + Canonicalized_Resource
The components that make up this structure are described in the following table:
||Required. The HTTP verb to be used with the signed URL.
Note: The HTTP verb
||Optional. The MD5 digest value in Base64. If you provide this in the string, the client (usually a browser) must provide this HTTP header with this same value in its request.|
||As needed. If you provide a content-type, the client (browser) must provide this HTTP header set to the same value.|
||Required. This is the timestamp (represented as the number of seconds since the Unix Epoch of 00:00:00 UTC on January 1, 1970) when the signature expires. The server rejects any requests received after this timestamp.|
||As needed. The server checks to make sure that the client provides matching values in requests using the signed URL. For information about how to create canonical headers for signing, see Canonical extension headers.|
||Required. The resource being addressed in the URL. For more details, see Canonical resources.|
Signing strings with the App Engine App Identity service
When creating a signed URL using a program, you can either sign the string from within your program, or else from within a Google App Engine application using the App Engine Identity service, which uses App Engine's service account credentials. For example, using the Python App Identity API, you can:
google.appengine.api.app_identity.sign_blob()to sign the bytes from your constructed string, providing the
Signatureyou need when assembling the signed URL.
google.appengine.api.app_identity.get_service_account_name()to retrieve a service account name, which is the
GoogleAccessIdyou need when assembling the signed URL.
The App Identity service rotates the private keys when it signs blobs. Signed URLs generated from the App Identity service are good for at least one hour, and are best used for short-lived access to resources.
Canonical extension headers
When creating a signed URL using a program, you construct the Canonical
Extension Headers portion of the message by concatenating all
extension (custom) headers that begin with
x-goog-. However, you cannot perform a simple
concatenation. Keep the following algorithm in mind as you create the headers:
Make all custom header names lowercase.
Sort all custom headers by header name using a lexicographical sort by code point value.
If present, remove the
x-goog-encryption-key-sha256headers. These headers contain sensitive information that must not be included in the string-to-sign; however, these headers must still be used in any requests that use the generated signed URL.
Eliminate duplicate header names by creating one header name with a comma-separated list of values. Be sure there is no whitespace between the values, and be sure that the order of the comma-separated list matches the order that the headers appear in your request. For more information, see RFC 7230 section 3.2.
Replace any folding whitespace or newlines (CRLF or LF) with a single space. For more information about folding whitespace, see RFC 7230, section 3.2.4.
Remove any whitespace around the colon that appears after the header name.
Append a newline "\n" (U+000A) to each custom header.
Concatenate all custom headers.
When creating a signed URL using a program, you construct the Canonicalized Resource portion of the message by concatenating the resource path (bucket and object and subresource) that the request is acting on. Keep the following in mind as you create the resource:
The canonical resource is everything that follows the host name. For example, if the Cloud Storage URL is
https://storage.googleapis.com/example-bucket/cat-pics/tabby.jpeg, then the canonical resource is
If the request is scoped to a subresource, such as
?cors, add this subresource, including the question mark, to the end of the string.
Be sure to copy the HTTP request path literally: that is, you should include all URL encoding (percent signs) in the string that you create. Also, be sure that you include only query string parameters that designate subresources (such as
cors). You should not include query string parameters such as