Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FR] Admin 'getDownloadURL' for Storage #1352

Closed
samtstern opened this issue Jun 30, 2021 · 16 comments · Fixed by #2036
Closed

[FR] Admin 'getDownloadURL' for Storage #1352

samtstern opened this issue Jun 30, 2021 · 16 comments · Fixed by #2036

Comments

@samtstern
Copy link
Contributor

Is your feature request related to a problem? Please describe.

Download URLs are one of the most convenient ways to display content from Cloud Storage for Firebase, but right now they can only be created on the client.

There has been extensive discussion of this on the Cloud side, and their basic stance is "we don't like the Firebase URLs and we don't think you should be able to make them": googleapis/nodejs-storage#697

As a result the best documentation on how to make these URLs on the server is this massive StackOverflow answer:
https://stackoverflow.com/questions/42956250/get-download-url-from-file-uploaded-with-cloud-functions-for-firebase/56010225#56010225

Describe the solution you'd like

A simple getDownloadURL() method in the Node.js Admin SDK

Describe alternatives you've considered

None

Additional context

None

@spotvin42
Copy link

I am also struggling with this and the community as well, we can see it on stackoverflow...

I've created my own way to get one following the described method in your shared link.

I think it's not right as one commenter from Google said, but I don't see another way?

https://stackoverflow.com/questions/70563169/resizing-images-already-on-google-storage-locally-through-sharpjs-and-keeping-u

Thank you in advance for supporting this issue!

@ArnabXD
Copy link

ArnabXD commented May 18, 2022

I found an interesting article regarding this

https://www.sentinelstand.com/article/guide-to-firebase-storage-download-urls-tokens

@samatcolumn
Copy link

Well I've got a new job but still running into this same issue, we'd love a simple way to generate download URLs for objects from our backend Node.js server. Right now we can only do this on our frontend.

I do understand there are many workarounds but we'd like the solution to be the same on frontend and backend, not have different types of URLs depending on where they were generated.

@lahirumaramba lahirumaramba self-assigned this May 18, 2022
@willbattel
Copy link

Yeah it's a bit ridiculous that we can't directly access the tokened URL from the Admin SDK. We want the token feature so we have the ability to revoke, as opposed to just making everything public. Ideally we would keep the URL in the associated Firestore document that we're already fetching on the client so we don't need to make extra round trip requests that needlessly slows down the application. I'm not sure why there has been so much pushback from Google on this- it feels like a major handicap to their Storage product that only the client SDKs can access the URL.

@samatcolumn
Copy link

samatcolumn commented May 19, 2022

We're using relatively old versions of Firebase (JS v8.3.3, Admin v9.4.2) so YMMV but I found that this workaround seems to get me what I want on the backend:

  const storage = admin.storage();
  const ref = storage.bucket(`gs://${bucket}`).file(pathToFile);
  const [metadata] = await ref.getMetadata();

  const token = metadata.metadata.firebaseStorageDownloadTokens;
  const link = `https://firebasestorage.googleapis.com/v0/b/${bucket}/o/${encodeURIComponent(
    pathToFile
  )}?alt=media&token=${token}

But it scares me that firebaseStorageDownloadTokens is undocumented and I can't figure out where that comes from or if it's guaranteed to exist in all situations (I assume not). I'd love to hear a Googler's perspective on this workaround at least.

@atif7865
Copy link

@lahirumaramba is this being looked at internally? Any updates?

@willbattel
Copy link

willbattel commented Apr 16, 2023

Looks like they are open to it in principle but are looking to change the mechanism internally this year so I guess we'll just have to wait and see what that means...

See: #2036 (review)

@tonyjhuang
Copy link

Hi, Firebaser here. Sorry for the radio silence and thanks for the continued interest in this FR. @willbattel is correct in that we are looking to offer alternatives to download urls in the future as there are some interesting security implications of this feature that makes it unideal in security-critical applications.

That being said, while we can't provide an estimated timeline on when it will become available, @maneesht is actively working on adding getDownloadUrl functionality to the admin SDK to bridge the gap in the meantime.

@dellumdeus
Copy link

dellumdeus commented Apr 21, 2023

Would be amazing if this PR#2036 gets merged soon👌

@samatcolumn
Copy link

Thank you @maneesht!!! Been wanting this feature for two years.

@MorenoMdz
Copy link

Is this released? If so how do we use it? The documentation don't mention this.

@Whimfoome
Copy link

Is this released? If so how do we use it? The documentation don't mention this.

import admin from 'firebase-admin';
import { getDownloadURL } from 'firebase-admin/storage';

const bucket = admin.storage().bucket('your-storage-bucket-url.appspot.com');
const file = bucket.file('path');
const downloadUrl = await getDownloadURL(file);

console.log(downloadUrl);

@tonyjhuang
Copy link

Thanks for the code sample @Whimfoome, our official docs have also been updated to include an example: https://firebase.google.com/docs/storage/admin/start#shareable_urls

jhengineerartist added a commit to jhengineerartist/art-website that referenced this issue Sep 2, 2023
firebase admin based backend.

I have an issue where the obtained signed URL links to
production google servers rather than the emulated storage,
and calling getDownloadURL to obtain the public url just
straight up crashes the emulator.

Some relevant links to investigate that particular issue.
firebase/firebase-admin-node#1352
firebase/firebase-tools#3396
invertase/react-native-firebase#6638
https://stackoverflow.com/questions/42956250/get-download-url
-from-file-uploaded-with-cloud-functions-for-firebase

This changelist will reproduce the issue if you try to change to
getDownloadURL or try to get an emulated storage url

THIS IS NOT A FUNCTIONAL CHANGELIST.
@samasthwafer
Copy link

I'm getting this massive error
`ApiError: Not Found.

 at new ApiError (/functions/node_modules/firebase-admin/node_modules/@google-cloud/storage/build/src/nodejs-common/util.js:80:15)
 at Util.parseHttpRespBody (//functions/node_modules/firebase-admin/node_modules/@google-cloud/storage/build/src/nodejs-common/util.js:215:38)
 at Util.handleResp (/home/hp/projects/functions/node_modules/firebase-admin/node_modules/@google-cloud/storage/build/src/nodejs-common/util.js:156:117)
 at /home/hp/projects/node_modules/@google-cloud/storage/build/src/nodejs-common/util.js:538:22
 at onResponse (/hom/functions/node_modules/retry-request/index.js:240:7)
 at /d/functions/node_modules/firebase-admin/node_modules/teeny-request/build/src/index.js:226:13
 at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {

code: 404,
errors: undefined,
response: PassThrough {
_events: {
close: undefined,
error: [ [Function (anonymous)], [Function (anonymous)] ],
prefinish: [Function: prefinish],
finish: undefined,
drain: undefined,
data: [Function (anonymous)],
end: [Function (anonymous)],
readable: undefined,
unpipe: undefined
},
_readableState: ReadableState {
highWaterMark: 16384,
buffer: [],
bufferIndex: 0,
length: 0,
pipes: [],
awaitDrainWriters: null,
[Symbol(kState)]: 194512764
},
_writableState: WritableState {
highWaterMark: 16384,
length: 0,
corked: 0,
onwrite: [Function: bound onwrite],
writelen: 0,
bufferedIndex: 0,
pendingcb: 0,
[Symbol(kState)]: 1091466620,
[Symbol(kBufferedValue)]: null
},
allowHalfOpen: true,
_maxListeners: undefined,
_eventsCount: 4,
statusCode: 404,
statusMessage: 'Not Found',
request: {
agent: Agent {
_events: [Object: null prototype] {
free: [Function (anonymous)],
newListener: [Function: maybeEnableKeylog]
},
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 443,
protocol: 'https:',
options: [Object: null prototype] {
maxSockets: Infinity,
keepAlive: true,
noDelay: true,
path: null
},
requests: [Object: null prototype] {},
sockets: [Object: null prototype] {},
freeSockets: [Object: null prototype] {
'firebasestorage.googleapis.com:443:::::::::::::::::::::': [ [TLSSocket] ]
},
keepAliveMsecs: 1000,
keepAlive: true,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 1,
maxCachedSessions: 100,
_sessionCache: { map: {}, list: [] },
[Symbol(shapeMode)]: false,
[Symbol(kCapture)]: false
},`

I had to remove a few parts in the url for security. I'm using busboy to upload the file to the backend and then I'm trying to use getDownloadUrl(fileref) to get a url.

@davit-b
Copy link

davit-b commented Mar 18, 2024

@samasthwafer that's an API error due to the object not being found. Make sure your platform (emulator or cloud) and the file actually exist.

@KishorJena
Copy link

KishorJena commented Jun 9, 2024

Is this released? If so how do we use it? The documentation don't mention this.

import admin from 'firebase-admin';
import { getDownloadURL } from 'firebase-admin/storage';

const bucket = admin.storage().bucket('your-storage-bucket-url.appspot.com');
const file = bucket.file('path');
const downloadUrl = await getDownloadURL(file);

console.log(downloadUrl);

Thanks for snippet. its like gem💎 in the corner.

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