1
votes

I have written a firebase Http callable cloud function based on the tutorial here: https://www.youtube.com/watch?v=3hj_r_N0qMs from the firebase team. However, my function is unable to verify the custom claims on a user (me) as 'context.auth' is undefined

I've updated firebase, firebase tools, firebase-functions and admin SDK to the latest versions.

My functions/Index.ts file

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

export const addAdmin = functions.https.onCall((data, context) => {
    if (context.auth.token.admin !== true) {
        return {
            error: 'Request not authorized'
        };
    }
    const uid = data.uid
    return grantAdminRole(uid).then(() => {
        return {
            result: `Request fulfilled!`
        }
    })
})

async function grantAdminRole(uid: string): Promise<void> {
    const user = await admin.auth().getUser(uid);
    if (user.customClaims && (user.customClaims as any).admin === true) {
        console.log('already admin')
        return;
    }
    return admin.auth().setCustomUserClaims(user.uid, {
        admin: true,
    }).then(() => {
        console.log('made admin');
    })
}

My app.component.ts code

makeAdmin() {
    var addAdmin = firebase.functions().httpsCallable('addAdmin');
    addAdmin({ uid: '[MY-USER-ID]' }).then(res => {
      console.log(res);
    })
    .catch(error => {
      console.log(error)
    })
  }

The function executes well if I don't try to access 'context' and I can add a custom claim to this user. However if I try to access context.auth I find the error:

Unhandled error TypeError: Cannot read property 'token' of undefined"
2

2 Answers

0
votes

The error message is telling you that context.auth doesn't have a value. As you can see from the API documentation, auth will be null if there is no authenticated user making the request. This suggests to me that your client app does not have a signed-in user at the time of the request to the callable function, so make sure that is the case before invoking the function. If you allow the case where a callable function can be invoked without a signed in user, you will need to check for that case in your function code by checking context.auth before doing work on behalf of that user.

0
votes

Turns out I wasn't properly integrating AngularFire Functions. I found the solution to my problem here: https://github.com/angular/angularfire2/blob/master/docs/functions/functions.md

I changed my client component code to the following:

import { AngularFireFunctions } from '@angular/fire/functions';

//other component code

makeAdmin() {
    const callable = this.fns.httpsCallable('addAdmin');
    this.data$ = callable({ uid: '[USERID]' })
      .subscribe(resp => {
        console.log({ resp });
      }, err => {
        console.error({ err });
      });
  }