In firebase - How to generate an idToken on the server for testing purposes?
Asked Answered
A

4

48

I want to test a a cloud function that creates users.

In normal cases, inside the browser i generate an idToken and i send it to server via headers: Authorization : Bearer etcIdToken

But I want to test this function without the browser. In my mocha tests i have:

before(done => {
   firebase = require firebase.. -- this is suppose to be like the browser lib.
   admin = require admin.. 

    idToken = null;
    uid = "AY8HrgYIeuQswolbLl53pjdJw8b2";
    admin.auth()
        .createCustomToken(uid)               -- admin creates a customToken
        .then(customToken => {
            return firebase.auth()            -- this is like browser code. customToken get's passed to the browser.
                .signInWithCustomToken(customToken)     -- browser signs in.
                .then(signedInUser => firebase.auth()             -- now i want to get an idToken. But this gives me an error.
                    .currentUser.getIdToken())
        })
        .then(idToken_ => {
            idToken = idToken_
            done();
        })
        .catch(err => done(err));
})

The error i'm getting is:

firebase.auth(...).currentUser.getIdToken is not a function - getting the idToken like this works on client - and is documented here.

I tried directly with signedInUser.getIdToken(). Same problem:

signedInUser.getIdToken is not a function - not documented. just a test.

I think this is because firebase object is not intended for node.js use like i'm doing here. When signing in - stuff get's saved in browser local storage - and maybe this is why.

But the question still remains. How can i get an idToken inside node.js in order to be able to test:

return chai.request(myFunctions.manageUsers)
    .post("/create")
    .set("Authorization", "Bearer " + idToken)   --- i need the idToken here -  like would be if i'm getting it from the browser.
    .send({
          displayName: "jony",
          email: "[email protected]",
          password: "123456"
    })

am I approaching this wrong? I know that if i can get the idToken it will work. Do i rely need the browser for this? Thanks :)

Ariew answered 15/1, 2018 at 18:8 Comment(3)
You're correct in saying that the Firebase web client SDK is not meant to run in node apps. Why don't you use the one of the documented Cloud Functions testing techniques and skip trying to emulate what a browser does? firebase.google.com/docs/functions/local-emulator firebase.google.com/docs/functions/unit-testingHeathcote
What version of firebase client library are you using? getIdToken was introduced in version 4.x.x.Versicolor
Hey, did you sort this out? I am dealing with the same.Transship
C
47

From Exchange custom token for an ID and refresh token, you can transform a custom token to an id token with the api. Hence, you just have to generate a custom token first from the uid, then transform it in a custom token. Here is my sample:

const admin = require('firebase-admin');
const config = require('config');
const rp = require('request-promise');

module.exports.getIdToken = async uid => {
  const customToken = await admin.auth().createCustomToken(uid)
  const res = await rp({
    url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${config.get('firebase.apiKey')}`,
    method: 'POST',
    body: {
      token: customToken,
      returnSecureToken: true
    },
    json: true,
  });
  return res.idToken;
};
Carnatic answered 15/7, 2018 at 8:49 Comment(1)
Anyone running in firebase auth emulator url: http://localhost:9099/www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${environment.firebase.apiKey}Floyd
L
9

L. Meyer's Answer Worked for me.

But, the rp npm package is deprecated and is no longer used. Here is the modified working code using axios.

const axios = require('axios').default;
const admin = require('firebase-admin');
const FIREBASE_API_KEY = 'YOUR_API_KEY_FROM_FIREBASE_CONSOLE';

const createIdTokenfromCustomToken = async uid => {
  try {
    const customToken = await admin.auth().createCustomToken(uid);

    const res = await axios({
      url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${FIREBASE_API_KEY}`,
      method: 'post',
      data: {
        token: customToken,
        returnSecureToken: true
      },
      json: true,
    });

    return res.data.idToken;

  } catch (e) {
    console.log(e);
  }
}
Lissy answered 17/5, 2021 at 17:24 Comment(0)
W
3
curl 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<FIREBASE_KEY>' -H 'Content-Type: application/json'--data-binary '{"email": "[email protected]","password":"test","returnSecureToken":true}'

If this curl doesn't run, try running the same thing on Postman. It works!

Wanderlust answered 22/4, 2021 at 5:52 Comment(0)
F
0

NOTE: the API endpoint has been changed from https://googleapis.com to https://identitytoolkit.googleapis.com, and you will get 404 error when you try to call the old endpoint.

The API spec is still remain the same, so all you have to do is to insert identitytoolkit. before the original hostname.

This is latest example code using ky:

const res = await ky
    .post(
        'https://identitytoolkit.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken',
        {
            searchParams: {
                key: FIREBASE_API_KEY,
            },
            json: {
                token: customToken,
                returnSecureToken: true,
            },
        },
    )
    .json();
Foxed answered 19/7, 2024 at 18:40 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.