Reputation: 729
I am very new to Firebase and custom claims, so I hope someone can help.
I have an app that uses Firebase Auth as its authentication system. The app is built using Flutter. It is a subscription-based app, so the users must have an 'active' subscription status, in order to be logged in. The subscription information for each user, including the status, is stored in a Firestore collection called 'subscriptions'. Each user is assigned a document with their uid as its name when they create a subscription.
The way my app works is that a user will create an account on the WordPress website, using Firebase authentication. At this point, their user is created in Firebase Auth, but they have no assigned document in the 'subscriptions' Firestore collection. This is only created once they purchase a subscription with WooCommerce Subscriptions. I basically need them to be prevented from logging in if:
As far as I know, the best way to allow users to log in only if they have an active subscription, is to use custom claims. I've built the following two custom claims functions in javascript with VS Code, which are designed to check the subscriptions collection in Firestore for the user's subscription status, both when the document is created and if it is updated:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
// Claim when a user is created
exports.createUser = functions.firestore
.document("subscriptions/{subscription}")
.onCreate((snap, context) => {
// Get an object representing the document
const newValue = snap.data();
// Access a particular field
const userId = newValue.firebaseUid;
console.log("New subscription ${UserId} created!");
const status = newValue.status;
// Assign claims to the user
return admin.auth().setCustomUserClaims(userId, {status});
});
// Claim when a user is updated
exports.updateUser = functions.firestore
.document("subscriptions/{subscription}")
.onUpdate((change, context) => {
// Get an object representing the document
const updatedValue = change.after.data();
// Access a particular field
const userId = updatedValue.firebaseUid;
console.log("User subscription status updated!");
const status = updatedValue.status;
// Assign claims to the user
return admin.auth().setCustomUserClaims(userId, {status});
});
For some reason, these aren't working. They did successfully upload to my project in the Firebase console. However, they aren't adding a custom claim to the standard auth claim. I was expecting to see 'status: active/pending/cancelled'
attached at the end of the claims map. They also aren't seemingly able to handle the case where no document exists for a user (i.e. when the user has only just created an account but hasn't yet subscribed).
Can someone show me why these aren't working and what I am doing wrong? How can I ensure the subscription status is added to my users' auth claims, so that I can guarantee they can only log in if they have an active subscription? Thanks!
Upvotes: 1
Views: 258
Reputation: 729
I realised that the main problem with my code above is that I was using the wrong Firebase user ID getter value. I am using the plugins from TechCater and the value firebaseUid
needed to be changed to firebase_user_id
. In addition, I combined the functions into one, using onWrite
instead of onCreate
and onUpdate
. The new/updated function, which works perfectly, looks like this:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
// Claim when a user is updated
exports.onUpdateUsers = functions.firestore
.document("subscriptions/{subscription}")
.onWrite((change, context) => {
// Get an object representing the document
const updatedValue = change.after.data();
if (updatedValue == null) {
return;
}
// Access a particular field
const userId = updatedValue.firebase_user_id;
console.log("User subscription status created or updated!");
console.log("User ID: ", userId);
const status = updatedValue.status;
console.log("Status: ", status);
// Assign claims to the user
return admin.auth().setCustomUserClaims(userId, {status});
});
What's more, with respect to my comment in my original question about how to create a custom claim when a user had signed up but not purchased a subscription, I realised that all I needed to do was understand that when a user has created their account, but not purchased a subscription, the subscription status would be returned as null
, so I just needed to check for the status being null
as well as 'active'
or other. The function now works exactly as I need it to.
Upvotes: 3