16

Using the new Firebase Cloud Functions in combination with the admin sdk.

I want to use the admin.auth().createCustomToken() function. Calling this function results in a error message

Error: createCustomToken() requires a certificate with "private_key" set.
    at FirebaseAuthError.Error (native)
    at FirebaseAuthError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:25:28)
    at new FirebaseAuthError (/user_code/node_modules/firebase-admin/lib/utils/error.js:90:23)
    at FirebaseTokenGenerator.createCustomToken (/user_code/node_modules/firebase-admin/lib/auth/token-generator.js:62:19)
    at Auth.createCustomToken (/user_code/node_modules/firebase-admin/lib/auth/auth.js:89:37)
    at /user_code/index.js:29:26
    at process._tickDomainCallback (internal/process/next_tick.js:129:7)

How do I config the cloud functions to use a private_key?

admin.initializeApp(functions.config().firebase);
Nicholas
  • 501
  • 2
  • 14
Frank Spin
  • 1,463
  • 15
  • 23
  • 1
    @davidtabmann: please don't tag with firebase-functions. Proper tagging for [Cloud Functions for Firebase](https://firebase.google.com/docs/functions/) is [google-cloud-functions][firebase]. Also see my answer here: http://stackoverflow.com/questions/42854865/what-is-the-difference-between-cloud-function-and-firebase-functions/42859932#42859932 – Frank van Puffelen Mar 20 '17 at 14:02
  • @FrankvanPuffelen , ok, I've indeed read that as stated [here](https://meta.stackoverflow.com/questions/345605/proposing-firebase-functions-tag), I was first waiting for an answer from you in there...Now it's very clear for me. – DavidTaubmann Mar 22 '17 at 11:44

2 Answers2

40

Unfortunately, the createCustomToken() method requires a private key to mint custom tokens, which is not currently available with the default credential (which happens to be an Application Default Credential). As noted in Create custom tokens using the Firebase Admin SDKs, you need to provide a certificate credential to be able to create custom tokens.

You can generate the certificate needed for this credential by following the instructions in Add Firebase to your app. Once you have the key JSON file, you need to get it into Cloud Functions for Firebase.

You can do this by storing the key JSON file in your /functions folder as service-account.json. Then, in the file where you define your Functions, use admin.credential.cert() to initialize the Admin SDK, like this:

const functions = require('firebase-functions');
const admin = require('firebase-admin');

var serviceAccount = require("./service-account.json");
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: functions.config().firebase.databaseURL
});

For a full example of how to do this, with more detailed instructions and a code sample, check out the Instagram sign in sample.

Note that we hope to add support for createCustomToken() from the default credential in the future, but for now, you will have to bring your own credential for this particular method to work.

mamu
  • 12,184
  • 19
  • 69
  • 92
jwngr
  • 4,284
  • 1
  • 24
  • 27
  • 7
    This solution works but is it secure to upload service-account.json with the source code? What about storing that json in firebase config? Which way is more secure? @frank-van-Puffelen – Muhammad Hassan Nasr Apr 13 '17 at 19:07
  • If I'm using two projects (dev and prod) do you recommend I conditionally initialize the app with the two different service-account.json files? – Celso Nov 29 '17 at 19:30
  • I would use functions.config().firebase.databaseURL to set databaseURL, so don't have to worry about different environments. Also set env variable for filename, so you can control which serviceaccount file goes with current env. functions:config:set – mamu Mar 08 '18 at 20:03
  • 1
    @MuhammadHassan, if you want to make it real tight and fancy then you can set all varibles for serviceaccount using current env. functions:config:set. This will keep service account details out of source code. – mamu Mar 08 '18 at 20:04
  • 2
    For future readers, this solution no longer works in this exact form with the 1.0.0 cloud-functions API because the ability to pass in a config object to `initializeApp` has been removed. I've asked a follow-up question here: https://stackoverflow.com/questions/49656429/generating-a-custom-auth-token-with-a-cloud-function-for-firebase-using-the-new – Murphy Randle Apr 04 '18 at 16:56
  • refer here: https://firebase.google.com/docs/auth/admin/create-custom-tokens#troubleshooting – Abhi Muktheeswarar Mar 01 '22 at 18:13
0

As stated here: https://firebase.google.com/docs/auth/admin/create-custom-tokens?authuser=0

To test the same code locally, download a service account JSON file and set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point to it.

Then in your code:

admin.initializeApp();

John Josef
  • 314
  • 2
  • 5