I have these Firestore rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isValidUser(userId) {
return request.auth.uid == userId && request.auth.role == 'user';
}
function isLoggedIn() {
return request.auth.uid != null;
}
match /users/{id}/{document=**}{
allow create, read, update, delete: if isLoggedIn() && isValidUser(id)
}
}
}
And I create a valid Firebase token via a Google cloud function and send it to whoever logs in successfully, like this
const firebaseToken = await admin.auth().createCustomToken(uuid);
return res.status(200).json({status: true, token: firebaseToken, id: uuid});
Now we go to Flutter, in main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
if (Firebase.apps.isEmpty) {
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
}
Instance.registerTypes(onRegister: (getIt) {
getIt.registerLazySingleton(() => BusinessDevice());
});
runApp(
Phoenix(
child: ProviderScope(
child: MyApp(),
),
),
);
}
And in login.dart
final headers = {'Content-Type': 'application/json'};
final request = http.Request(
'POST', Uri.parse(ENDPOINTS.FIREBASE_AUTH));
request.body = json.encode({
"email": userCtrl.text.trim(),
"password": passCtrl.text.trim(),
"role": "user"
});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
final body = await response.stream.bytesToString();
final jsonResponse = json.decode(body);
if (response.statusCode == 200) {
// Authentication succeeded, store the token and navigate to the dashboard
final token = jsonResponse['token'];
final userid = jsonResponse['id'];
await FirebaseAuth.instance.signInWithCustomToken(token);
DocumentSnapshot<Map<String, dynamic>> snap = await FirebaseFirestore.instance
.collection('users').doc(userid).get();
}
I'm getting this error when the application tries to read from Firestore
FirebaseException ([cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.)
We're using signInWithCustomToken()
, because we have a username and password authentication system, which isn't supported out of the box by Firebase so I had to write a Google cloud function to handle this.
I'm looking for a solution that will require the fewest changes in the codebase. Because we are facing the same issue in 3 different big apps in production and Firestore is used on all the pages. I want to work on securing the apps and not refactoring them.
It looks like your role
is a custom claim, in which case it exists in the token
property in your rules. So:
return request.auth.uid == userId && request.auth.token.role == 'user'
// 👆
Also see:
request.auth