Skip to content
This repository was archived by the owner on Mar 31, 2026. It is now read-only.
This repository was archived by the owner on Mar 31, 2026. It is now read-only.

Impossible to use signed url v4 and the Service Account Credential APIs #355

Description

@guillaumeblaquiere

Months ago, I solved an issue to a Stack overflow user by explaining how to generate a signed URL without a service account JSON fey file. I also release an article on this

Today, a comment of a user told me that is doesn't work. They open a new Stack Overflow question and in their question, there is the v4 mentioned.

I dug into the code and yes, the v2 and the v4 haven't the same behavior: the v4 check if the credential can generate a signed URL by itself, that implies the useless check later that allows to use Service Account Credential API, instead of the service account private key to generate the signature.

Environment details

  • Linux (Cloud Function and Cloud Run)
  • Python version: python --version 3.7 and 3.8
  • google-cloud-storage version: latest (1.35.0)

Steps to reproduce

  1. Working code on Cloud Run (for example) Replace YOUR_BUCKET by a valid bucket
import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def sign_url():
    from google.cloud import storage
    from datetime import datetime, timedelta

    import google.auth

    credentials, project_id = google.auth.default()

    # Perform a refresh request to get the access token of the current credentials (Else, it's None)
    from google.auth.transport import requests
    r = requests.Request()
    credentials.refresh(r)

    client = storage.Client()
    bucket = client.get_bucket('YOUR_BUCKET')
    blob = bucket.get_blob('name.csv')

    service_account_email = credentials.service_account_email

    url = blob.generate_signed_url(service_account_email=service_account_email, access_token=credentials.token,version="v2", method="PUT",expiration=timedelta(minutes=120),content_type="application/octet-stream")
    return url, 200

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

  1. Broken code on Cloud Run (for example) Replace YOUR_BUCKET by a valid bucket
import os
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def sign_url():
    from google.cloud import storage
    from datetime import datetime, timedelta

    import google.auth

    credentials, project_id = google.auth.default()

    # Perform a refresh request to get the access token of the current credentials (Else, it's None)
    from google.auth.transport import requests
    r = requests.Request()
    credentials.refresh(r)

    client = storage.Client()
    bucket = client.get_bucket('YOUR_BUCKET')
    blob = bucket.get_blob('name.csv')

    service_account_email = credentials.service_account_email

    url = blob.generate_signed_url(service_account_email=service_account_email, access_token=credentials.token,version="v4", method="PUT",expiration=timedelta(minutes=120),content_type="application/octet-stream")
    return url, 200

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

Only the version (v2/v4) has changed

Fix proposal is coming.

Activity

  1. added
    priority: p2Moderately-important priority. Fix may not be included in next release.
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    and removed
    🚨This issue needs some love.
    triage meI really want to be triaged.
    on Jan 11, 2021
  2. nagro-c commented on Jan 19, 2021

    @nagro-c

    I'm facing the same issue on cloud function env, and getting the error below:

    AttributeError: you need a private key to sign credentials.the credentials you are currently using <class 'google.auth.compute_engine.credentials.Credentials'> just contains a token. see https://googleapis.dev/python/google-api-core/latest/auth.html#setting-up-a-service-account for more details.

  3. deepamgupta commented on Sep 1, 2021

    @deepamgupta

    @guillaumeblaquiere
    after applying the fix provided by you, I am getting this exception
    <class 'google.auth.exceptions.RefreshError'>, RefreshError('invalid_scope: Invalid OAuth scope or ID token audience provided.', '{"error":"invalid_scope","error_description":"Invalid OAuth scope or ID token audience provided."}'), <traceback object at 0x7f4d783cc680>

    at the line credentials.refresh(r)

    Any idea?

  4. guillaumeblaquiere commented on Sep 1, 2021

    @guillaumeblaquiere
    ContributorAuthor

    @deepamgupta can you describe your runtime context? Is it on your workstation? On Compute Engine? elsewhere?

  5. deepamgupta commented on Sep 1, 2021

    @deepamgupta

    @guillaumeblaquiere Currently I am working on my Laptop. Using Pycharm debugger to run a flask application.

  6. marcusbevans commented on Mar 7, 2023

    @marcusbevans

    I ran into the same problem trying to run a simple FastAPI app on Cloud Run just today. Just an FYI that the problem still exists.

    Also, thank you for your article. It allowed me to build the work around.

  7. carlthome commented on Mar 21, 2023

    @carlthome

    Same issue here with v4 and FastAPI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    api: storageIssues related to the googleapis/python-storage API.priority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions