Prepare and test your skills
Prepare and test your skills
A V4 signed URL for Cloud Storage (opens in a new tab) is a complete XML API URL that embeds authentication in its query string. The URL is created by a service account that already has permission for the action, and it lets a person without Google credentials perform one specific action on one object for a limited time. Anyone who holds the URL can use it while it is active, and Cloud Storage verifies the signature before serving the request.
A V4 signed URL consists of a resource URL plus six X-Goog-* query parameters that define who signed it, what must match, and how long it lasts. The resource part identifies the bucket and object, such as https://storage.googleapis.com/example-bucket/cat.jpeg, while the query string carries the authorization. All query parameters included at signing time are covered by the signature, so a later request that adds an unsigned query parameter will fail.
X-Goog-Algorithm: signing algorithm, such as GOOG4-RSA-SHA256 for RSA keys with x-goog-* extensions.X-Goog-Credential: signer identity and credential scope, including client email, date, location, service, and request type.X-Goog-Date: time the URL became usable, in ISO 8601 basic format YYYYMMDD'T'HHMMSS'Z', such as 20181026T181309Z.X-Goog-Expires: lifetime in seconds measured from X-Goog-Date, such as 900 for 15 minutes.X-Goog-SignedHeaders: lowercased headers that must be sent with the request, such as host or content-type;host.X-Goog-Signature: hex-encoded authentication string computed over the string-to-sign.The credential value links the signature to a specific day and scope, for example example@example-project.iam.gserviceaccount.com/20181026/us-central1/storage/goog4_request. Programmatic signing builds the same scope as DATE/LOCATION/storage/goog4_request, where sample code uses auto as the location. Because the date in the scope must match the day in X-Goog-Date, the URL cannot be shifted to a different day without breaking the signature.
The canonical request is the standardized description of the intended request that gets hashed and signed. The canonical request for Cloud Storage captures the HTTP method, the canonical URI derived from the escaped object name such as /{escaped_object_name}, ordered canonical headers, the list of signed headers, and the canonical query string. Canonical headers are built by lowercasing header names and values, sorting headers by name, combining duplicates with comma-separated values, normalizing whitespace, and ending each header line with a newline.
The hash of that canonical request is placed inside a UTF-8 encoded string-to-sign with four lines in order:
GOOG4-RSA-SHA256 for RSA keys or GOOG4-HMAC-SHA256 for HMAC keys with x-goog-* extensions.X-Goog-Date.The signer applies the signing algorithm to the signing key and string-to-sign, then hex-encodes the message digest to produce X-Goog-Signature. For RSA signing the service account private key signs directly, while for HMAC signing the key secret is first derived through chained HMAC-SHA256 operations over date, location, service, and request type. The final URL appends the signature as X-Goog-Signature=REQUEST_SIGNATURE with a query string that matches the canonical request exactly.
The HTTP method in a V4 signed URL defines the exact operation the holder is allowed to perform. The actual request must use the same method that was signed, and a mismatch between the signed method and the sent method causes signature verification to fail. Signed headers add precision by requiring the client to send the same headers that were signed.
| Signed method | Intended action | Typical signed headers |
|---|---|---|
| GET | Download and read object data such as cat.jpeg | host |
| PUT | Upload object data such as cat.png, including overwrites when permitted | content-type;host |
This binding lets parameters such as response-content-disposition be included at signing time to override object metadata for an authenticated GET without allowing other changes. For resumable uploads, a signed URL is generally needed only for the initial POST that starts the session, because later PUT requests use the returned session URI as their authentication token. The session URI flows from the server that initiated the upload to the client that sends the data, and like a signed URL it must be shared over HTTPS because anyone holding it can upload.
Expiration in a V4 signed URL is controlled by the pair X-Goog-Date and X-Goog-Expires. X-Goog-Date is the start time and X-Goog-Expires is the number of seconds after that start time that the URL remains valid. Common lifetimes include 600 seconds for 10 minutes, 900 seconds for 15 minutes, and 3600 seconds for one hour. The signature is usable starting 15 minutes before the active datetime and ending at the expiration time, so clocks that are slightly early can still succeed while late requests are rejected.
Access ends when the expiration time passes or when the key used to sign the URL is rotated. Because anyone with the URL can use it during its window, shorter lifetimes reduce the risk of unwanted sharing. The signing account must itself hold the permission for the signed action, such as storage.objects.get for downloads or storage.objects.create for uploads.
Exam tip: The longest X-Goog-Expires value for a Cloud Storage V4 signed URL is 604800 seconds (7 days); longer requested lifetimes are rejected.
Identity delegation with signed URLs lets a service account (opens in a new tab) lend its identity for time-limited access to Cloud Storage objects. A program creates a signature on behalf of the service account, and anyone holding the resulting URL can perform the allowed operation without needing a Google identity. The signature is valid only for the constraints encoded in the URL, such as the resource, HTTP method, and expiration time.
The service account is the signing identity for a Cloud Storage signed URL because its email appears in the URL credential and its key creates the request signature. Cloud Storage verifies the signature against that service account when the URL is used, so the URL carries the authority of the service account for one specific operation. This delegation allows external users, mobile clients, or browsers without Google credentials to read or write an object directly. The delegation ends when the URL expires, and it never grants broader access to the account.
A valid signed URL requires two separate Identity and Access Management (IAM) permissions to work together. The caller who creates the signature must be allowed to impersonate the service account, and the service account itself must be allowed to perform the Cloud Storage operation that the URL will authorize. If either side is missing, signing itself is denied or use of the URL fails.
Prepare the service account before implementing the V4 signing process:
The human or workload that signs needs the Service Account Token Creator role on the service account, while the service account itself needs the Cloud Storage permission for the operation, such as reading object data.
The Service Account Credentials API (opens in a new tab) signs data on behalf of a service account without exposing its private key to the caller. The caller invokes the signBlob method for binary blobs or the signJwt method for JSON Web Tokens through the REST endpoint, the gcloud beta iam service-accounts sign-jwt command, or a client library such as IamCredentialsClient.SignBlob() or sign_jwt(). To use these approaches, the caller must be a member of the Service Account Token Creator role, which includes the iam.serviceAccounts.signBlob permission to generate valid signatures.
A successful signBlob response contains a signedBlob value and the keyId of the system-managed private key that was used. The signedBlob value can be used as a bearer token to directly authenticate a request on behalf of the service account, and the token remains valid until that system-managed private key expires. When calling the API with a client library, the service account name must use the wildcard character - for the project, in the form projects/-/serviceAccounts/my-service-account@my-project.iam.gserviceaccount.com, and a name that includes the project ID in the path is invalid.
Implementation strategies and security constraints for signed URLs cover how to create time-limited, delegated access to objects for users without Google identities. A Cloud Storage (opens in a new tab) signed URL is generated by an authorized signer and lets anyone who holds the URL read or write a specific object until the URL expires. The signer remains the trust boundary, the holder of the URL gets temporary access without an account, and Cloud Storage enforces the expiration and signature on every request.
Cloud Storage client libraries are the application path for generating signed URLs inside code. The application first authenticates with Application Default Credentials, which by default come from the environment or from the default App Engine service account, and the client then signs a URL for a specific bucket and object. Data flows from the signing service account to the generated URL to the end user, and the end user presents the URL directly to Cloud Storage without calling Google authentication. This approach depends on the signer having permission to access the object, typically storage.objects.get for reads, and on credentials being available through GOOGLE_APPLICATION_CREDENTIALS or the runtime service account.
Programmatic generation fits dynamic workloads where URLs must be created per user, per object, or per request. Supported client libraries span many languages:
storage.Client() and Ruby Google::Cloud::Storage.new patterns that look for credentials in the environment when none are passed explicitlyBecause the code controls the object name, HTTP method, expiration time, and signed headers, applications can enforce least privilege for each URL at creation time.
Command-line tools are the operator path for generating access and moving objects without writing application code. The Google Cloud CLI with gcloud storage cp and gsutil-style workflows runs as an authenticated operator and is useful for testing access, debugging, and one-off sharing. Traffic flows from the operator workstation to Cloud Storage, and a generated URL or copied object can then be handed to another person or piped to a process such as gcloud storage cp gs://BUCKET_NAME/OBJECT_NAME - | PROCESS_NAME.
Choose command-line generation when a person needs quick, manual access rather than automated per-request URLs. Choose client libraries when an application must generate many URLs, embed generation in request handling, or apply consistent expiration and header policies. The operational tradeoff is control versus convenience: code gives repeatable policy enforcement, while the command line gives speed for administration and troubleshooting.
Expiration limits and canonical headers are the two security constraints that keep a signed URL from becoming open-ended access. The expiration time defines the window during which Cloud Storage accepts the URL, and shorter windows reduce harm if a URL is forwarded, logged, or leaked. First the signer picks an expiration that matches the task, then Cloud Storage rejects the URL only after that time passes, so access automatically returns to expired without revoking keys or changing permissions.
Canonical headers bind the signed request to specific HTTP headers, such as content type or custom metadata, that must match exactly when the URL is used. The signer includes those header names and values in the signature, the holder must send the same headers back to Cloud Storage, and any added, removed, or altered header causes signature validation to fail. Use canonical headers when uploads or downloads must not be modified in transit, and keep expirations as short as the workflow allows to prevent unauthorized reuse.
Access control boundaries for signed URLs mean the URL does not replace bucket permissions. The signer must already be authorized and the bucket policy determines what the signature can delegate. The permission to read objects comes from Identity and Access Management roles such as Storage Object Viewer (roles/storage.objectViewer), which contains storage.objects.get, while console browsing also needs listing permissions found in Storage Admin (roles/storage.admin). The required permissions for object access include:
storage.objects.get to read object datastorage.buckets.list to browse buckets in the consolestorage.objects.list to list objects in the consoleService accounts are the preferred signer identity, and persistent service account keys should be avoided in favor of Application Default Credentials, impersonation, or workload identity federation. For bucket-level control, uniform bucket-level access is preferred over access control lists (ACLs) because ACLs apply per bucket or object, are limited to 100 entries, cannot cover projects or non-storage resources, and can bypass domain restrictions and interact unexpectedly with IAM conditions.
Exam tip: Enable uniform bucket-level access to prevent ACL usage; use ACLs only when per-object customization or XML API interoperability requires them.
X-Goog-Signature, and the request must match what was signed.X-Goog-Expires value for a Cloud Storage V4 signed URL is 604800 seconds (7 days).iam.serviceAccounts.signBlob, while the service account itself needs the Cloud Storage permission for the operation.signBlob or signJwt without exposing the private key, and client library resource names must use projects/-/serviceAccounts/ with - as the project wildcard.A Cloud Storage V4 signed URL consists of a resource URL that identifies the bucket and object plus six X-Goog query parameters that define who signed it, what must match, and how long it lasts. The parameters are X-Goog-Algorithm, X-Goog-Credential, X-Goog-Date, X-Goog-Expires, X-Goog-SignedHeaders, and X-Goog-Signature, and all query parameters included at signing time are covered by the signature so a later request that adds an unsigned query parameter will fail.
Expiration in a Cloud Storage V4 signed URL is controlled by X-Goog-Date as the start time and X-Goog-Expires as the number of seconds after that start time that the URL remains valid. The longest X-Goog-Expires value is 604800 seconds (7 days) and longer requested lifetimes are rejected, and the signature is usable starting 15 minutes before the active datetime and ending at the expiration time.
A valid Cloud Storage signed URL requires the caller who creates the signature to be allowed to impersonate the service account and the service account itself to be allowed to perform the Cloud Storage operation that the URL will authorize. The signing caller needs the Service Account Token Creator role which includes iam.serviceAccounts.signBlob, while the service account needs the Cloud Storage permission for the operation such as storage.objects.get for downloads or storage.objects.create for uploads.
Last updated