Error: com.google.firebase.FirebaseException: No AppCheckProvider installed - firebase

i need to delete a file from firebase storage, i am following this code:
static deleteFile(String urlFile) async {
try {
final ref = FirebaseStorage.instance.refFromURL(urlFile);
await ref.delete();
} catch (e) {
if (kDebugMode) {
print(e.toString());
}
}
}
the file is deleted, but the console displays this error:
W/StorageUtil(13434): Error getting App Check token; using placeholder token instead. Error: com.google.firebase.FirebaseException: No AppCheckProvider installed.
the user is successfully authenticated.

App Check Attestation Providers:
For IOS: DeviceCheck or App Attest &
For Android: Play Integrity or SafetyNet
Use Anyone of these you like, I personally use SafetyNet for my android apps.
Add this inside apps/build.gradle:
dependencies {
implementation 'com.google.firebase:firebase-appcheck-safetynet:16.0.0'
}
Then Initialize App Check Add this:
FirebaseApp.initializeApp(/context=/ this);
FirebaseAppCheck firebaseAppCheck = FirebaseAppCheck.getInstance();
firebaseAppCheck.installAppCheckProviderFactory(
SafetyNetAppCheckProviderFactory.getInstance());
I hope it fix your error. for more you can follow official doc: [https://firebase.google.com/docs/app-check/android/safetynet-provider].
Another Temporary fix... for TP & Practice Apps
Simply Remove If Condition from your firebase storage/db/auth rules
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if false;
}
}
}

Related

How to set Firebase Database URL (Unity)

I'm trying to create a login with Facebook with Firebase.
My login function is:
public void FacebookLogin()
{
var perms = new List<string>() { "public_profile", "email" };
FB.LogInWithReadPermissions(perms, AuthCallback);
if (FB.IsLoggedIn)
{
string aToken = Facebook.Unity.AccessToken.CurrentAccessToken.UserId;
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Firebase.Auth.Credential credential = Firebase.Auth.FacebookAuthProvider.GetCredential(aToken);
auth.SignInWithCredentialAsync(credential).ContinueWith(task => {
if (task.IsCanceled)
{
Debug.LogError("SignInWithCredentialAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInWithCredentialAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
newUser.DisplayName, newUser.UserId);
});
}
}
My problem is the warning "Database URL not set in the Firebase config.", followed by a SignInWithCredentialAsync error (System.AggregateException).
How can I change the URL in Firebase config? Where is this Firebase config located?
I'm a newbie in coding, thanks for the support.
I should manage to link all the Id app, Oauth etc correctly( i hope so), I believe the problem is caused by the empty URL for firebase db.
firebaser here
There is a bug in the Firebase games SDKs at the moment, which makes it require that a databaseURL value is specified in the google-services.json and/or google-services-info.plist files. Unfortunately that key is not present anymore, unless you actually use the Realtime Database.
The easiest might be to:
Create a Realtime Database instance in the Firebase console.
Download the updated configuration files and add them to your project again.
Update: I just spotted that the issue on Github also mentions a workaround for the problem.

Firebase Storage security rules and download tokens for uploaded files

TLDR: This is a question about the URL returned from the task.snapshot.ref.getDownloadURL() and its respective downloadToken. It asks about what is the main role and functionality of the token and if it's necessary for files that will be publicly available by security rules.
I've just finished the tutorial guides about uploading and downloading files to Firebase Storage found on https://firebase.google.com/docs/storage/web/upload-files and also on this Youtube tutorial from the Firebase official channel.
I'm building a Content Management System for a blog section in one of my Firebase web apps (React + Firebase).
I have a component that lets the admin pick an image and upload it to Firebase Storage Bucket to be displayed in a specific blog post. All images to a specific blogPost should be inside a folder for the specific blog-post-slug.
Example:
//bucket/some-blog-post-slug/image1.jpg
Code that runs whenever the admin selected a new file on the <input type='file'/>:
function onFileSelect(e) {
const file = e.target.files[0];
const storageRef = firebase.storage().ref('some-slug/' + file.name);
const task = storageRef.put(file);
task.on('state_changed',
function progress(snapshot) {
setPercent((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
},
function error(err) {
console.log(err);
},
function complete() {
console.log('Upload complete!');
task.snapshot.ref.getDownloadURL().then(function(downloadURL) {
console.log('File available at', downloadURL);
props.changeImageSrc(downloadURL);
});
}
);
}
The code above returns the downloadURL that will be saved to the Firestore inside the blogPost document.
The downloadURL has the following format:
https://firebasestorage.googleapis.com/v0/b/MYFIREBASEAPP.appspot.com/o/some-slug%2FILE_NAME.jpg?alt=media&token=TOKEN_VALUE
You can see that it comes with a "basic URL": https://firebasestorage.googleapis.com/v0/b/MYFIREBASEAPP.appspot.com/o/some-slug%2FILE_NAME.jpg
And the basicURL is appended with the following GET parameters:
alt=media and token=TOKEN_VALUE
I was not aware that I would be getting a token, so I'm now testing its behavior to know more about it.
BEHAVIOR WITH STORAGE READS ALLOWED:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}}}
When I access the basicURL:
I get an object in response with the uploaded file details:
{
"name": "some-slug/FILE_NAME.jpg",
"bucket": "MYBUCKET",
"generation": "GENERATION_NUMBER",
"metageneration": "1",
"contentType": "image/jpeg",
"timeCreated": "2019-06-05T13:53:57.070Z",
"updated": "2019-06-05T13:53:57.070Z",
"storageClass": "STANDARD",
"size": "815155",
"md5Hash": "Mj4aCPs21NUNxXpKg1bHirFIO0A==",
"contentEncoding": "identity",
"contentDisposition": "inline; filename*=utf-8''FILE_NAME.jpg",
"crc32c": "zhkQMQ==",
"etag": "CKu4a1+u2+0ucI412CEAE=",
"downloadTokens": "TOKEN_VALUE"
}
When I access the basicURL?alt=media
The image is displayed.
When I access the basicURL?alt=media&token=TOKEN_VALUE
The image is displayed.
BEHAVIOR WITH STORAGE READS RESTRICTED:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}}}
When I access the basicURL:
I get the following error object:
{
"error": {
"code": 403,
"message": "Permission denied. Could not perform this operation"
}
}
When I access the basicURL?alt=media
I get the same error object:
{
"error": {
"code": 403,
"message": "Permission denied. Could not perform this operation"
}
}
When I access the basicURL?alt=media&token=TOKEN_VALUE
The image is displayed.
CONCLUSION AND QUESTIONS
It seems to me that the security rule allow read: if request.auth != null; should have blocked any reads from unauthorized users, but with the TOKEN parameter, the file is accessible even for requests without an auth object (Note: I wasn't logged in when I ran the tests above).
I know it's not the best practice to ask more than 1 question, but in this case I think it's necessary:
QUESTION 1:
What is this TOKEN mainly used for and why does it overried the auth rule?
QUESTION 2:
I want these images to be publicly availabe, as the blog section will be for all users. What URL should I save to Firestore?
Option 1: allow the reads for everyone and just save the basicURL.
Option 2: keep the reads restricted and save the basicURL + token.
QUESTION 3:
To display the images in <image src="imgSrc"> tags do I need the alt=media parameter? Or the basicURL ending in the FILE_NAME is good enough?
EDIT: QUESTION 3 ANSWER: Just tested it and found out that the alt=media GET parameter IS necessary to display the image inside an <img> tag.
NOTE: if you upload the same file and replace the old one, you'll get a different token each time and the older token becomes invalid.
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
This is security permissions for Firebase Storage. All Types of Data(Images, Video etc)
Unfortunately, described method from https://firebase.google.com/docs/storage/web/create-reference does not add authorization data to request and storage rule like
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
returns permission denied,
using AngularFireStorage module resolves this issue.
import { AngularFireStorage } from '#angular/fire/storage';
constructor(
private storage: AngularFireStorage
) {
}
getFileUrl(path: string): Observable<string> {
const storageRef = this.storage.ref(path);
return from(storageRef.getDownloadURL());
}

Error on uploading file to firebase cloud storage: "Listing objects in a bucket is disallowed for rules_version = 1"

I've setup firebase auth and cloud storage on my application. Whenever I try to upload a file, however, I'm getting an error I can't find any information about. The error is a 400: Bad Request with the following message
Listing objects in a bucket is disallowed for rules_version = "1". Please update storage security rules to rules_verison = "2" to use list.
I can't seem to find anything about updating security rules_version. Note, when I look at the firebase console, the upload actually successfully goes through, but the HTTP return is still the error above. What does it mean by listing objects, and how can I update my security rules?
For more information, my upload code (in Kotlin) is
fun uploadImage(uri: Uri, path: String): Task<Uri> {
val storageRef = FirebaseStorage.getInstance().reference
val storagePath = storageRef.child(path)
return storagePath.putFile(uri).continueWithTask{ storageRef.downloadUrl }
}
I call it with
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode in 0..2 && resultCode == Activity.RESULT_OK) {
val cropImageUri = CropImage.getActivityResult(data).uri
val systemTime = System.currentTimeMillis()
val path = "$userId/$systemTime"
//IMAGE UPLOAD HERE:
FirebaseImageResource.uploadImage(cropImageUri, path)
.addOnCompleteListener {
if (it.isSuccessful) {
GlideApp.with(this)
.load(cropImageUri)
.into(imageViewForPosition(requestCode)!!)
imageUris[requestCode] = it.result.toString()
}
}
}
}
My firebase rules are the default:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I'm also successfully authing with Facebook Login
override fun onSuccess(loginResult: LoginResult) {
val credential = FacebookAuthProvider.getCredential(loginResult.accessToken.token)
auth.signInWithCredential(credential)
}
(It lacks a success listener right now, but I know it's working because when I don't use it, I get an unauthorized error instead, and the file doesn't actually upload)
You need to prepend this to your Firebase Storage rules:
rules_version = '2';
An example is this:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I suspect that this is a case of a not-so-helpful error message.
Just replace your upload code from
fun uploadImage(uri: Uri, path: String): Task<Uri> {
val storageRef = FirebaseStorage.getInstance().reference
val storagePath = storageRef.child(path)
return storagePath.putFile(uri).continueWithTask{ storageRef.downloadUrl }}
to
fun uploadImage(uri: Uri, path: String): Task<Uri> {
val storageRef = FirebaseStorage.getInstance().reference
val storagePath = storageRef.child(path)
return storagePath.putFile(uri).continueWithTask{ storagePath.downloadUrl }}
I solved it with the following setps
Sign in Firebase console
Select project
Click Storage button
Select Rules tab
Insert top "rules_version = '2';"

How to force logout firebase auth user from app remotely

I have a project which uses firebase auth with firebaseUI to authenticate users. I have enabled Google, Facebook and email providers. What I need is to remotely logout or disable some of the users.
I want the users to logout from the app on doing so. I tried disabling the user in the firebase console and also used the firebase admin SDK (https://firebase.google.com/docs/auth/admin/manage-sessions) to revoke the refresh tokens.
I waited for more than 2 days and still noticed that the user was logged in and could access the firestore data.
I have also gone through and tried
Firebase still retrieving authData after deletion
Can anyone point to what I am doing wrong ?
You also cannot remotely force a user to be signed out. Any sign out will have to happen from the device that the user is signed in on.
There is no way to revoke an access token once that is minted. This means that even if you disable the user's account, they may continue to have access for up to an hour.
If that is too long, the trick (as also mentioned in my answer to the question you linked) is to maintain a list of blocked users in your database (or elsewhere) and then check against that in your security rules (or other authorization layer).
For example in the realtime database, you could create a list of blocked user's UIDs:
banned_uids: {
"uid1": true
"uid2": true
}
And then check against that in your security rules with:
".read": "auth.uid !== null && !root.child('banned_uids').child(auth.uid).exists()"
You can send a message data with FCM to force to log out.
For example, if the users use android application.
Save the FCM token in a collection in firebase Realtime.
configure the Android client app, in the service. LINK You have to make when receive a message with especial string, force to log out.
make the trigger you need in cloud functions, to send the data LINK when you need the user log out.
SUCCESS!
As per your scenarios, i assume that you need to make user logout when user is disabled.
Use One global variable to store TokenNo (might be in shared preference or sqlite):
Add following code to your manifest:
<service android:name=".YourFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Add following code in your
public class LogoutOntokenchange extends FirebaseMessagingService{
#Override
public void onNewToken (String token){
if(TokenNo=>1){ //if tokenNo >=1 means he already logged in
TokenNo=0;
FirebaseAuth.getInstance().signOut(); //Then call signout method
}
else{
TokenNo=1; //store token no in db
}
}
}
What Happens here:
When user logged in first time onNewToken is called then It goes into else then TokenNo is updated to 1 from 0.
When You disable any user then automatically token is refreshed.Then OnNewToken is called then TokenNo>=1 so user will be logged out.
NOTE: When user log in for first time i.e if TokenNo variable is not stored then store it as 0.
For reference: https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService
The only way I can think about is adding a if-else block in your starting activity.
Store the that status of user (verified/banned/deleted) in Firebase Real-time database. Then retrieve the status of user at start of application and add the code:
if (currentUserStatus.equals("banned"))
{
currentUser.logout();
}
What I've done is I created for each user upon registration a Firestore document with the UID as document ID. In this document I store an array which stores all fcm tokens the individual user receives when logging into a new device. That way I always keep track where the user is logged in. When the user logs out manually the fcm token will be deleted from the document in Firestore as well as on the device.
In order to be able to log out the user everywhere they are signed in I did the following. When starting the app and once the user is logged in I start a snapshot listener that listens to all changes in the users document. As soon as there is a change I retrieve the new array of fcm tokens, search inside the array for the local current device fcm token. If found, I do nothing. If the fcm token is no longer in the array I will call the local logout method and go back to the login screen.
Here are the methods I used in swift on iOS. The closures (passOnMethod) will just trigger an unwind segue to the login view controller.
import Foundation
import Firebase
class FB_Auth_Methods {
let db = Firestore.firestore()
var listener: ListenerRegistration?
func trackLoginStatus(passOnMethod: #escaping () -> () ) {
listener?.remove()
if let loggedInUserA_UID = Auth.auth().currentUser?.uid {
listener = db.collection(K.FStore.collectionOf_RegisteredUsers_Name)
.document(loggedInUserA_UID)
.addSnapshotListener { (snapshotDocument, error) in
if let error = error {
print(error)
} else {
if let document = snapshotDocument {
if let data = document.data() {
if let fcmTokens = data[K.FStore.Users.fcmTokens] as? [String] {
print("Found the following tokens: \(fcmTokens)")
self.compareTokensAgainstCurrentDeviceToken(fcmTokens: fcmTokens, passOnMethod: { () in
passOnMethod()
})
}
}
}
}
}
}
}
func compareTokensAgainstCurrentDeviceToken(fcmTokens: [String], passOnMethod: #escaping () -> () ) {
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print(error)
} else if let result = result {
if fcmTokens.contains(result.token) {
print("Token found, doing nothing")
} else {
print("Token no longer found, logout user")
do {
try Auth.auth().signOut()
InstanceID.instanceID().deleteID { error in
if let error = error {
print(error)
} else {
passOnMethod()
}
}
} catch let signOutError as NSError {
print (signOutError)
}
}
}
}
}
}
And here is the method I use when logging out the user everywhere but at the current device.
func deleteAllFcmTokensExceptCurrent(loggedInUserA: User, passOnMethod: #escaping () -> () ) {
InstanceID.instanceID().instanceID { (result, error) in
if let error = error {
print(error)
} else if let result = result {
let batch = self.db.batch()
let deleteAllFcmRef = self.db.collection(K.FStore.collectionOf_RegisteredUsers_Name).document(loggedInUserA.uid)
batch.updateData([K.FStore.Users.fcmTokens: FieldValue.delete()], forDocument: deleteAllFcmRef)
let updateFcmTokenRef = self.db.collection(K.FStore.collectionOf_RegisteredUsers_Name).document(loggedInUserA.uid)
batch.updateData([K.FStore.Users.fcmTokens: FieldValue.arrayUnion([result.token])], forDocument: updateFcmTokenRef)
batch.commit { (error) in
if let error = error {
print(error)
} else {
passOnMethod()
}
}
}
}
}
Not tested yet, as our backend programmer, who is in charge of setting up Firestore rules was gone for the day, but in theory this should work: (and it's something I'll test tomorrow)
Having a FirebaseAuth.AuthStateListener in charge of serving UI based on the status of the user
This combined with rules in firestore
match /collection
allow read: if isAuth();
Where isAuth is:
function isAuth() {
return request.auth.uid != null;
}
If the user is then disabled, while being logged in, whenever the user tries to read data from the collection, he should be denied, and a signOut() call should be made.
The AuthStateListener will then detect it, and sign the user out.

Firebase JS Error: getToken aborted due to token change

I'm getting a Firebase error "Error: getToken aborted due to token change" while running Firestore transaction using the JavaScript library. The error doesn't get thrown every time and I couldn't find the pattern. I suppose I've implemented some race conditions somewhere.
The user flow in my app goes like this:
Register a new account & submit an additional string in the same form
Log user in after registration using the same credentials
After log in, take that additional string and save it to Firestore (in a transaction).
Transaction fails due to Error: getToken aborted due to token change.
The flow of promises:
firebase.auth().createUserWithEmailAndPassword(email, password)
.catch(signupError => {
// no problems here
})
.then(() => {
return firebase.auth().signInWithEmailAndPassword(email, password)
})
.catch(loginError => {
// no problem here
})
.then((user) => {
// Database write call which fails (see lower code block)
return this.claimInput.writeClaimedPlace(user.user.uid, claimedPlace);
})
.catch(error => {
// "getToken aborted" ERROR GETS CAUGHT HERE, transaction fails
})
}
The database transaction call
firestore.runTransaction(function(transaction) {
return transaction.get(usersBusinessRef).then(function(usersBusinesDoc) {
let claimedPlaces = [];
if (usersBusinesDoc.exists && usersBusinesDoc.data().claimedPlaces) {
claimedPlaces = usersBusinesDoc.data().claimedPlaces;
}
claimedPlaces.push(claimedPlace);
return transaction.set(usersBusinessRef, { claimedPlaces }, { merge: true });
});
});
I couldn't find the error anywhere on google.
I'm thinking the error is caused by the token change that happens at log in. On the other hand I'm reading that Firebase accepts old tokens for a few more moments. Any thoughts?
I got a similar error[error code] while debugging my client which was connecting to firebase via a React App.
The solution was
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write: if false;
}
}
}
Putting the above inside the rules part of the firestore settings which apparently means you need to allow reads for external apis but writes are blocked and it was previously blocking both reads and writes.
This could be one of the issues if you are trying to read from your client/server
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read;
allow write;
}
}
}
DISCLAIMER: * I am not an Expert at firebase. I am not sure if this would compromise your DB to be written by external apis since you are opening your firestore firewall by doing this
P.S. there is a firebase-admin module which I think helps in doing writes by handling authentication in a separate fashion. I think that module is more suited for writes and the normal firebase.firestore(app) is for reads.

Resources