1
votes

I am trying to read from this google storage bucket:

https://storage.googleapis.com/images.eng.channelmeter.com/avatars/d2d48e49-82be-4cf6-be6e-11ada43c7339

But I am getting this error:

nice colorful error image

the error is like so:

<Error>
<Code>AccessDenied</Code>
<Message>Access denied.</Message>
<Details>
Anonymous caller does not have storage.objects.get access to images.eng.channelmeter.com/avatars/d2d48e49-82be-4cf6-be6e-11ada43c7339.
</Details>
</Error>

How can I obtain an access token that I can append to url? Something like this:

https://storage.googleapis.com/images.eng.channelmeter.com/avatars/d2d48e49-82be-4cf6-be6e-11ada43c7339?access_token="XXX"

I assume I can make some call using an OAuth library to get a temporary / one-time access token, anyone know how?

Update: I can get an AccessToken using this technique: https://tanaikech.github.io/2018/12/11/retrieving-access-token-using-service-account-by-googles-oauth2-package-for-golang/

but then when I add the ?access_token=xxx to the URL, I now just get:

<Error>
<Code>AccessDenied</Code>
<Message>Access denied.</Message>
</Error>

damn.

1
note for service accounts (which can access G Cloud Storage) we only need access on a per-application basis? developers.google.com/identity/protocols/oauth2#serviceaccountuser13307220
In your example, you seem to be making raw REST requests. Can you clarify where you are making the GCS object access calls from and from what programming language and environment?Kolban
I am using golang to obtain an access token like so: tanaikech.github.io/2018/12/11/… .....so . I have an access token, given a service account credentials file. Ultimately I want to make a GET request to retrieve an image from GCS. But I get "Access Denied"user13307220
Does your service account have the storage.objects.get permission (Storage Object Viewer role) on the bucket?norbjd
Hi @cholosrus Welcome to Stackoverflow! Could you please confirm which is the official URL from Cloud Storage that you are trying to access via Rest? Is it the URL https://storage.googleapis.com/images.eng.channelmeter.com/avatars/d2d48e49-82be-4cf6-be6e-11ada43c7339? If so, could you please provide more information on where you get the information that this bucket is accessible from a third-party account?gso_gabriel

1 Answers

0
votes

I reproduced your use case. Assuming you have a key.json file of a service account with the wright permissions on the bucket.

To authorize requests from the command line or for testing, you can use the curl command with the following syntax:

curl -H "Authorization: Bearer ACCESS_TOKEN" "https://storage.googleapis.com/storage/v1/b/example-bucket/o"

For local testing, you can use the gcloud auth application-default print-access-token command to generate a token.

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "net/http"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
    "golang.org/x/oauth2/jwt"
    "log"
)


func serviceAccount(credentialFile string) (*oauth2.Token, error) {
    b, err := ioutil.ReadFile(credentialFile)
    if err != nil {
        return nil, err
    }
    var c = struct {
        Email      string `json:"client_email"`
        PrivateKey string `json:"private_key"`
    }{}
    json.Unmarshal(b, &c)
    config := &jwt.Config{
        Email:      c.Email,
        PrivateKey: []byte(c.PrivateKey),
        Scopes: []string{
            "https://www.googleapis.com/auth/cloud-platform",
        },
        TokenURL: google.JWTTokenURL,
    }
    token, err := config.TokenSource(oauth2.NoContext).Token()
    if err != nil {
        return nil, err
    }
    return token, nil
}

func main() {
    token, err := serviceAccount("key.json") // Please set here
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }


    url := "https://storage.googleapis.com/storage/v1/b/your-bucket/o/your-file?alt=media"

    // Create a Bearer string by appending string access token
    var bearer = "Bearer " + token.AccessToken

    // Create a new request using http
    req, err := http.NewRequest("GET", url, nil)

    // add authorization header to the req

    req.Header.Add("Authorization", bearer)

    // Send req using http Client
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        log.Println("Error on response.\n[ERRO] -", err)
    }

    body, _ := ioutil.ReadAll(resp.Body)
    log.Println(string([]byte(body)))

}