4

My firebase cloud function contains protected routes that can only be accessed when passed a valid IdToken in the request header. cloud functions API looks like this

functions/index.js


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

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
  databaseURL: "DB_URL"
});

const express = require('express');
const app = express();


const authenticate = async (req, res, next) => {
  if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
    res.status(403).send('Unauthorized');
    return;
  }
  const idToken = req.headers.authorization.split('Bearer ')[1];
  try {
    const decodedIdToken = await admin.auth().verifyIdToken(idToken);
    req.user = decodedIdToken;
    next();
    return;
  } catch(e) {
    res.status(403).send('Unauthorized');
    return;
  }
};

app.use(authenticate);


app.get('/protected', async (req, res) => {
    return res.send('OK');
});

exports.api = functions.https.onRequest(app);

Initially, I was using the Firebase Authentication to create new user and to get IdToken

Creating new user

curl 'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]' \
-H 'Content-Type: application/json' \
--data-binary '{"email":"[user@example.com]","password":"[PASSWORD]","returnSecureToken":true}'

Getting IdToken so I can pass it to the firebase cloud functions to access the protected routes

curl 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]' \
-H 'Content-Type: application/json' \
--data-binary '{"email":"[user@example.com]","password":"[PASSWORD]","returnSecureToken":true}'

calling my protected cloud functions using this approach is working fine

curl --location --request GET 'http://localhost:5001/abc-production/us-central1/api/protected/' \
--header 'Authorization: Bearer SECRET_ID_TOKEN'

Now, Instead of using the Firebase Authentication, I'd like to use the Authentication Emulator to create new users and generate IdToken's.

UI auth emulator

I can create new users using the Auth emulator UI, but how do I generate the access token of those users? Are there any API endpoints that can return the IdToken of the locally saved user so that I can test my protected API without adding users in production?

Also, When I run the auth emulator, IdToken's generated using the production Firebase Authentication environment doesn't work.

"code": "auth/argument-error",
        "message": "Firebase ID token has invalid signature. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token."
Naresh
  • 941
  • 9
  • 22

2 Answers2

3

I just answered a very similar question here. The answer is the same so sorry if I'm duplicating...

Basically, to authenticate a user you can make the following HTTP POST request (assuming your Authentication emulator runs on port 9099): http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=any_key_you_want

Body (JSON):

{
  "email": "your-user@mail.com",
  "password": "some-password"   
}
Daniel Muñoz
  • 1,374
  • 12
  • 18
0

The emulator is intended only for local testing and not for production and you cannot use the IdToken issued by the emulator to access other services like Firebase Functions because and as the documentation says:

For security reasons, the Authentication emulator issues unsigned ID Tokens which are only accepted verifyIdToken and createSessionCookie of the Firebase Admin SDK when running inside the Cloud Functions emulator.

So, these token are only valid in the emulator environment and if you want to use them with Firebase Function, you can do that only with the Functions emulator. check this guide on how to run the functions locally.

Methkal Khalawi
  • 2,368
  • 1
  • 8
  • 13
  • 1
    I'm running the firebase functions in the emulator as well. It's just all my functions are protected and they can only be accessed by passing a valid token in the authentication header. My question was how to generate accessToken for the users stored in auth emulator. I don't want to create users in the production environment just to test my functions in the local environment – Naresh Feb 17 '21 at 03:49
  • you can try the solution mentioned here --> [How to get an idToken that is valid for development from firebase without having to spin up my frontend?](https://stackoverflow.com/questions/65973685/how-to-get-an-idtoken-that-is-valid-for-development-from-firebase-without-having) in which you just need to fake a creation of a user in your functions and sends back the token for that user – Methkal Khalawi Feb 22 '21 at 15:57
  • That answer suggests using `firebase/app` but as far as I know it can only be used in the frontend environment. Thanks though! appreciate your help. – Naresh Feb 23 '21 at 04:24
  • you are correct, this will create a user on client side not in your functions but the the idea still holds true as you can use the token produced from this example in your app for testing purposes. – Methkal Khalawi Feb 23 '21 at 14:50
  • that is a way to go but again I don't want to be dependent on the frontend to test my backend services. I created two different firebase projects one for production and another for development and also getting rid of the emulators – Naresh Feb 24 '21 at 04:52