0
votes

Can someone help me? All I want to do is update the JWT claims in a Firebase function. So I can set flag like IsAdmin etc and use it in the realtime DB. I have seen this article https://firebase.google.com/docs/auth/admin/custom-claims but I can't get any combination to work.

This is my firebase function call that I am making after sign in. Is this problem related to debugging locally? Can I test this locally?

import * as functions from 'firebase-functions';

const cors = require('cors');
const corsHandler = cors({origin: true});
const admin = require('firebase-admin');

admin.initializeApp();

export const resetClaims = functions.https.onRequest((req : any, res : any) => {
    corsHandler(req, res, () => {

        admin.auth().verifyIdToken(req.header("authorization").replace("Bearer ", '')).then((claims : any) => {
            var uid = claims.uid;

            admin.auth().setCustomUserClaims(uid, {test: true}).then(() => {
                // The new custom claims will propagate to the user's ID token the
                // next time a new one is issued.
              }).catch((er : any)=>{
                res.end(JSON.stringify({
                    status: er
                }));
                return;
            });
              return;
    });


});

I am calling this locally from a firebase web app. Using the following code

    const resetClaims = async ()=> {
        const fn = firebase.functions().httpsCallable('resetClaims');
        const res = await fn();
        firebase.auth().currentUser.getIdToken(true);
        alert(res.data.status);
    }

firebase.auth().onAuthStateChanged(function (user) {
            if (user) {
                resetClaims();
                setUsername(user.displayName);
            } else {
                setUsername('');
            }
        });

The http post works. But returns the following when debugging locally.

{"status":{"code":"app/invalid-credential","message":"Credential implementation provided to initializeApp() via the \"credential\" property failed to fetch a valid Google OAuth2 access token with the following error: \"Error fetching access token: Error while making request: getaddrinfo ENOTFOUND metadata.google.internal metadata.google.internal:80. Error code: ENOTFOUND\"."}}

1
Please edit the question to be more clear about the steps you're taking to invoke this function. Also, you should be aware that you should only initialize the Admin SDK once. Calling it with every function invocation is probably not a good idea.Doug Stevenson
Thanks will make this change. At this point I am just trying to get it to work.Anubis
What exactly are you doing when "debugging locally". Please be specific. Are you using the Firebase emulator suite? How are you invoking the function?Doug Stevenson

1 Answers

1
votes

You resetClaims Cloud Function is declared as an HTTP Cloud Function, since you do:

export const resetClaims = functions.https.onRequest(...)

but in your front-end you call it as if it was a Callable Cloud Function.

You should adapt your Cloud Function along the following lines:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

export const resetClaims = functions.https.onCall((data, context) => {

    const uid = context.auth.uid;

    return admin.auth().setCustomUserClaims(uid, {test: true})
    .then(() => {      
       return {result: "successful"};
    })
    .catch(error => {
       //See  https://firebase.google.com/docs/functions/callable#handle_errors
    });

});

Note that, as explained in the doc:

Callables have these key difference from HTTP functions:

  • With callables, Firebase Authentication and FCM tokens, when available, are automatically included in requests.
  • The functions.https.onCall trigger automatically deserializes the request body and validates auth tokens.

and

Authentication / user information is automatically added to the request (context parameters represent user auth information)