Get Public URL from file uploaded with firebase-admin

I've been tinkering with this for days and realized

A) correct access rights on the bucket is key:

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
      allow write: if request.auth != null;
    }
  }
}

B) The functional public URL is right there in the meta data (tested and works). Notice the access rights.

  const pdfDoc = printer.createPdfKitDocument(docDefinition);
  const pdfFile = admin
      .storage()
      .bucket()
      .file(newId + '.pdf');

    pdfDoc.pipe(
      pdfFile.createWriteStream({
        contentType: 'application/pdf',
        public: true,
      })
    );
    pdfDoc.end();

    console.log('Get public URL');
    const publicUrl = pdfFile.metadata.mediaLink;

What worked for me is to compose a URL like this:

https://storage.googleapis.com/<bucketName>/<pathToFile>

Example: https://storage.googleapis.com/mybucket.appspot.com/public/myFile.png

How I found it?

I went to GCP Console, Storage. Located the uploaded file. Clicked "Copy URL".

You may want to make a file Public first. I did it like this:

const bucket = seFirebaseService.admin().storage().bucket()
await bucket.file(`public/myFile.png`).makePublic()

From the sample application code on the using Cloud Storage documentation, you should be able to implement the following code to obtain the public download URL after the upload is successful:

// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream();

blobStream.on('finish', () => {
    // The public URL can be used to directly access the file via HTTP.
    const publicUrl = format(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
    res.status(200).send(publicUrl);
});

Alternatively, if you need a publicly accessible download URL, see this answer which suggests using getSignedUrl() from the Cloud Storage NPM module because the Admin SDK doesn't support this directly:

You'll need to generate a signed URL using getSignedURL via the @google-cloud/storage NPM module.

Example:

const gcs = require('@google-cloud/storage')({keyFilename: 'service-account.json'});
// ...
const bucket = gcs.bucket(bucket);
const file = bucket.file(fileName);
return file.getSignedUrl({
  action: 'read',
  expires: '03-09-2491'
}).then(signedUrls => {
  // signedUrls[0] contains the file's public URL
});