0

I have a FE application written in Rescript which handles uploading files to our Firebase storage in GCP and returns a download URL. The URL contains a token (without expiration date) which allows anyone that has the link to download the file. The code goes something like this:

let storageRef = Firebase.Storage.makeRef(storage, `${id}/${filename}`)
Firebase.Storage.getDownloadURL(storageRef)->Promise.then(url =>...)

The result URL is something like:

firebasestorage.googleapis.com/v0/b/{my-bucket}/o/{object-path}?alt=media&token={some-token}

Now I'm writing a golang script to migrate some files into our storage. I figured out how to upload the file and obtain a download URL but it's very different from the URL that rescript code is obtaining. My code looks like this:

config := &firebase.Config{
    StorageBucket: myBucketName,
}
app, err := firebase.NewApp(context.Background(), config, option.WithCredentialsFile(myServiceAccountKeyFileName))
if err != nil {
    log.Fatalf("error initializing app: %v\n", err)
}

client, err := app.Storage(context.Background())
if err != nil {
    log.Fatalf("error initializing storage client: %v\n", err)
}

file, err := os.Open(myFilePath)
if err != nil {
    log.Fatalf("error opening file: %v\n", err)
}
defer file.Close()

ctx := context.Background()

bucket, err := client.DefaultBucket()
if err != nil {
    log.Fatalf("error getting default bucket: %v\n", err)
}

object := bucket.Object(myFilePath)
writer := object.NewWriter(ctx)

if _, err := io.Copy(writer, file); err != nil {
    log.Fatalf("error uploading file: %v\n", err)
}

if err := writer.Close(); err != nil {
    log.Fatalf("error closing writer: %v\n", err)
}

fmt.Println("File uploaded successfully")

downloadURL, err := bucket.SignedURL(object.ObjectName(), &storage.SignedURLOptions{
    Expires: time.Now().AddDate(100, 0, 0),
    Method:  "GET",
})
if err != nil {
    log.Fatalf("error getting download URL: %v\n", err)
}

But the download URL is in a completely different form:

https://storage.googleapis.com/{my-bucket-name}/{filename}?Expires={timestamp}&GoogleAccessId={my-service-account}&Signature={long-signature}

while the URL is working and allows me to download the file, it has completely different structure from the one above. How do I make the Go code to upload the files and retrieve a download URL in the same format as from Rescript code?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
IFeel3
  • 167
  • 1
  • 13

1 Answers1

0

That first URL is a so-called download URL as generated by the Firebase SDKs to provide public, read-only access to a file.

The second URL is a so-called signed URL as generated by the Google Cloud SDKs to provide public read and/or write access to a file.

There is no way to generate a download URL from the Google Cloud SDKs, but there is a trick that allows you to generate such a URL yourself by setting the firebaseStorageDownloadTokens metadata on the file. For an example of this, see these answers to: Get Download URL from file uploaded with Cloud Functions for Firebase

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • The thread you linked suggest that the firebaseStorageDownloadTokens is no longer supported and was never documented... So there is no way to get the URL other than using javascript SDK? – IFeel3 Apr 18 '23 at 14:49
  • As far as I know, setting the `firebaseStorageDownloadTokens` still works. Give it a try. – Frank van Puffelen Apr 18 '23 at 15:37