8

Im trying to get a signedurl from a file in firebase/gc storage. All other solutions that i could find was to create a service account, download the service key, and use it in my app, but ive done that, and im still getting the error. Ive followed this advice also and added relevant roles to my service account SigningError with Firebase getSignedUrl().

The client_email property is in the service key that im using.

Pretty new to service accounts and gc so i may be missing something simple.

I am able to list the buckets, and all other requests to cloud firestore are working. Its just the signedurl for specific files is proving very difficult to retrieve.

Been driving me a bit loopy so any help would be great.

Heres my code.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const { Storage } = require('@google-cloud/storage');

const serviceAccount = require('./emom-84ee4-firebase-adminsdk-2309z-aab93226ec.json');
const keyfileName = require('./emom-84ee4-ac9e94667d5e.json');

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
    databaseURL: "https://emom-84ee4.firebaseio.com"
});

const storage = new Storage({
    projectId: 'emom-84ee4',
    keyFileName: keyfileName,
    // TRIED THIS ALSO => keyFileName: serviceAccount
});

const typeDefs = gql`
    type DownloadURL {
        url: String
    }

    type Comment {
        artist: String,
        comment: String,
        userId: String,
        replies: [Comment]
    }

    type Track {
        album: String,
        artist: String,
        artistId: String,
        description: String,
        genre: String,
        id: ID,
        title: String,
        duration: Int,
        comments: [Comment]
    }
    type User {
        artist: String,
        artistImageUrl: String,
        artistName: String,
        bio: String,
        location: String,
        userId: String,
        website: String
    }
    type Query {
        tracks: [Track]
        users: [User]
        downloadUrl: DownloadURL
    }
`

const resolvers = {
    Query: {
        async tracks() {
            const tracks = await admin
            .firestore()
            .collection('tracks')
            .get();
        return tracks.docs.map(track => track.data());
    },
    async users() {
        const users = await admin
            .firestore()
            .collection('users')
            .get();
            return users.docs.map(user => user.data());
    },
    // ISSUE HAPPENING HERE
    async downloadUrl() {
        try {
            const signedUrl = await storage
                .bucket('emom-84ee4.appspot.com')
                .file('tracks/ds5MaDn5ewxxvV0CK9GG.mp3')
                .getSignedUrl({ action: 'read', expires: '10-25-2022' });
            const url = signedUrl;
            console.log(url)
            return url;
        } catch (error) {
            console.error(error);
        }
    }
    }
}

const app = express();
const server = new ApolloServer({ typeDefs, resolvers });

server.applyMiddleware({ app, path: '/', cors: true });

exports.graph = functions.https.onRequest(app);
Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
bcooley1983
  • 172
  • 3
  • 12
  • 1
    Hey @bcooley1983 did you find a solution to your problem? Running into the same issue and can't get my head around it... – Arnaud B Nov 26 '20 at 17:40
  • I ditched firebase alltogether in favour of a graphql apollo server and Google cloud storage backend. So no, im sorry i never found a solution. Good luck with it. – bcooley1983 Nov 27 '20 at 21:36

2 Answers2

7

I was getting "Cannot sign data without client_email" error when running firebase emulators:start.

I fixed it by setting up a service account and downloading the service account .json credentials file as service_account.json, then running GOOGLE_APPLICATION_CREDENTIALS="service_account.json" firebase emulators:start

cgenco
  • 3,370
  • 2
  • 31
  • 36
2

You will need to add your service account key when you initialize your app.

var admin = require("firebase-admin");

var creds = require("[path to your serviceAccountKey.json]");

admin.initializeApp({
  credential: admin.credential.cert(creds),
});

If you don't have a service account, you can read how to get it here

or use https://console.firebase.google.com/project/**YOUR_PROJECT**/settings/serviceaccounts/adminsdk

Abraham
  • 12,140
  • 4
  • 56
  • 92