Cannot access Firebase Storage with or without authentication (web) - javascript

I want to use Firebase Storage (web version 9.6.0) but the access to Firebase Storage is being denied with the following error:
unhandledRejection: FirebaseError: Firebase Storage: User is not authenticated, please authenticate using Firebase Authentication and try again. (storage/unauthenticated)
You would want to say to me that I just need the user to be authenticated, but two problems:
the user is already authenticated (getAuth().currentUser returns something)
the rules in Firebase Storage don't say that a user needs to be authenticated:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read: if true;
allow write: if request.auth != null;
}
}
}
The problem is caused when I try this:
// initializeApp(config) etc.
const storage = getStorage() // enabled in Firebase console
const a_correct_path = "something..."
const reference = ref(storage, a_correct_path) // this is working (I get the right reference)
const url = getDownloadURL(reference) // this throws the error
NOTE: Because I have already had problems with it, please not that I'm using App Check which I have enforced for the Storage feature.
Why did I do wrong?

Firstly,
The
const a_correct_path = ""
Can't be empty and should have the correct path if it's in a folder.
But if that doesn't help... Reset your storage rules to the first one.
If that doesn't work, check the line where you imported things from firebase

On the Firebase Console, go to Authentication. Check that the user that you are logged in with appears there. If the user is not there then that means you are not authenticating users with Firebase Authentication, and maybe you're just adding users to your Firestore. That is why the error is placing emphasis on Firebase Authentication.
User is not authenticated, please authenticate using Firebase Authentication and try again.

Related

How to Delete or Disable User Account using uid in Firebase 9 using javascript? [duplicate]

Is there a way I can get a specific user account from firebase and then delete it?
For instance:
// I need a means of getting a specific auth user.
var user = firebase.auth().getUser(uid);
// Note the getUser function is not an actual function.
After, I want to delete that user and their additional data:
// This works
user.delete().then(function() {
// User deleted.
var ref = firebase.database().ref(
"users/".concat(user.uid, "/")
);
ref.remove();
});
Firebase Documentation states that users can be deleted if they are currently logged in:
firebase.auth().currentUser.delete()
My aim is to allow logged in admin user to delete other users from the system.
When using the client-side SDKs for Firebase Authentication, you can only delete the user account that is currently signed in. Anything else would be a huge security risk, as it would allow users of your app to delete each other's account.
The Admin SDKs for Firebase Authentication are designed to be used in a trusted environment, such as your development machine, a server that you control, or Cloud Functions. Because they run in a trusted environment, they can perform certain operations that the client-side SDKs can't perform, such as deleting user accounts by simply knowing their UID.
Also see:
delete firebase authenticated user from web application
Another common approach is to keep a allowlist/blocklist in for example the Firebase Database and authorize user based on that. See How to disable Signup in Firebase 3.x
I know this is an old question, but I found another solution to this.
You definitely don't want to use firebase-admin in your application itself, as I think was suggested by Ali Haider, since it needs a private key which you don't want to deploy with your code.
You can however create a Cloud Function in Firebase that triggers on the deletion of a user in your Firestore or Realtime database and let that Cloud Function use firebase-admin to delete the user.
In my case I have a collection of users in my Firestore with the same userid's as created by Firebase Auth, in which I save extra user data like the name and the role etc.
If you're using Firestore as me, you can do the following. If you're using Realtime database, just look up in the documentation how to use a trigger for that.
Make sure your Firebase project has cloud functions initialized. There should be a folder named 'functions' in your project directory. If not: initialize Cloud Functions for your project with the following command: firebase init functions.
Obtain a private key for your service account in the Firebase Console on the following page: Settings > Service accounts.
Place the json-file containing the private key in the functions\src folder next to the index.ts file.
Export the following function in index.ts:
export const removeUser = functions.firestore.document("/users/{uid}")
.onDelete((snapshot, context) => {
const serviceAccount = require('path/to/serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<DATABASE_NAME>>.firebaseio.com"
});
return admin.auth().deleteUser(context.params.uid);
});
Now deploy your Cloud Function with the command firebase deploy --only functions
When a user is deleted in your Firebase Firestore, this code will run and also delete the user from Firebase Auth.
For more information on Firebase Cloud Functions, see https://firebase.google.com/docs/functions/get-started
Just apply this code same way that you have done authentication.
var user = firebase.auth().currentUser;
user.delete().then(function() {
// User deleted.
}).catch(function(error) {
// An error happened.
});
Using the Javascript API (not the admin SDK)
Like this answer points out for user sign in, a second app must be created to be able to delete another user than the one logged in.
This is how I did it:
async deleteUser (user) {
// Need to create a second app to delete another user in Firebase auth list than the logged in one.
// https://stackoverflow.com/a/38013551/2012407
const secondaryApp = firebase.initializeApp(config, 'Secondary')
if (!user.email || !user.password) {
return console.warn('Missing email or password to delete the user.')
}
await secondaryApp.auth().signInWithEmailAndPassword(user.email, user.password)
.then(() => {
const userInFirebaseAuth = secondaryApp.auth().currentUser
userInFirebaseAuth.delete() // Delete the user in Firebase auth list (has to be logged in).
secondaryApp.auth().signOut()
secondaryApp.delete()
// Then you can delete the user from the users collection if you have one.
})
}
In my opinion, you can delete specific user without Firebase Admin SDK. You must to storage Username, Password of accounts you want to manage. And login with account - you declare a admin account. After that just follow steps: using firebase auth to logout -> using firebase auth to login with account you want to delete -> using firebase auth to delete that account -> using firebase auth to logout -> login again with that "admin account". Hope this solution help you to delete accounts without using Firebase Admin SDK

Active Directory access Azure Storage from browser

I want to use Azure Active Directory to allow users to read and write to Azure storage (specifically all Blobs and Tables) from a single-page web app.
I started like this:
import { InteractiveBrowserCredential } from '#azure/identity';
import { TableClient, TableServiceClient } from '#azure/data-tables';
const credentials = new InteractiveBrowserCredential({
clientId: myAuthConfig.clientId,
tenantId: myAuthConfig.tenantId,
});
const client = new TableServiceClient(
`https://${myAuthConfig.storageAccountName}.table.core.windows.net`,
credentials
);
client.listTables().byPage().next().then(console.log);
This works totally fine! I can see all the tables on the account. But then I wanted to list some of the data in on of the tables. So I did:
const client = new TableClient(
`https://${myAuthConfig.storageAccountName}.table.core.windows.net`,
'<table name>',
credentials
);
client.listEntities().byPage().next().then(console.log);
But this gives an error:
{
"odata.error": {
"code":"AuthorizationPermissionMismatch",
"message": {
"lang":"en-US",
"value":"This request is not authorized to perform this operation using this permission.\nRequestId:<uuid>\nTime:2021-10-28T18:04:00.0737419Z"
}
}
}
I'm very confused by this error. As far as I can tell I've done everything right. I followed every tutorial. I've set up active directory permissions for my app to use the storage API, my Microsoft account has permission to access the tables, OCRS is enabled, etc.
I'm not sure why I would have access to see a table but not see what's in it. I tried to use InteractiveBrowserCredential.authenticate to explicitly set scopes like this:
const scopes = ["User.Read"]
credentials.authenticate(scopes).then(console.log);
It works fine for User.Read but I couldn't figure out what scopes corresponded to Storage read/write access. If I added a scopy like "Microsoft.Storage" it told me that it didn't exist
Has anyone got an error like this before? What am I supposed to do here?
Thank you #gaurav mantri ,Posting your suggestion in comment as an answer.
From error it looks like your service principal does not have access permission to your table storage data. You should either grant permission using a RBAC role on the storage account resource (add to storage account contributors or readers) as below. Or use Storage Explorer to grant permission.
In your storage account please check, if you have Storage Table Data Contributer /Storage table data reader roles assigned as commented by #gaurav mantri
If not , you can add them
go into your storage account > IAM > Add role assignment, and add the special permissions
If roles are already assigned , the issue might be due to storage account being protected by firewall. Please try configure in Firewall and virtual networks of your storage account to add an existing virtual network or create a new vnet.If there is no issue you may allow access from all networks.
References:
Authorize access to tables using Active Directory - Azure Storage |
Microsoft Docs
Assign an Azure role for access to table data using powershell -
Azure Storage | Microsoft Docs

Sending ID token to signInSuccessUrl in firebaseui

I'm using firebaseUI to sign in users to my web app. I am using the redirect option. Upon successful sign in, the users are redirected to signInSuccessUrl, which is the admin page of my web app. However, I want to be able to pass the ID token associated with the user to the admin endpoint, where it can be authenticated and checked whether the user trying to log in has admin permissions or not (this I do by checking the user permissions in my database).
I've considered a few other options, namely:
Using firebase.auth().onAuthStateChanged on the admin page itself, checking if the user is signed in, and making a request to the backend to check if the user is an admin. If these conditions are met, render the page, otherwise, show permission denied.
The problem with this approach is that:
It moves a significant part of the auth to the client side
I can't restrict access at the endpoint level itself. In contrast, if I send an ID token, I can check if the user is an admin or not and accordingly decide what to render, instead of always rendering the admin page and then checking on the client side if the user is logged in and is an admin.
Making a dummy page in between the firebase sign-in page and the admin home page. This dummy page would check if the user is signed in using onAuthStateChanged as mentioned above, make a request to the backend to check if the user has admin permissions, and based on the results, redirect to either the admin home page or show permission denied and go back to the login page.
This is how the config would look like if I do this:
var uiConfig = {
signInSuccessUrl: '/admintestpage/',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID
]
}
The /admintestpage/ endpoint would render test.html, which would have code something like:
<script type="text/javascript">
initApp = function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
idToken = user.getIdToken();
/*Send idToken to a backend api to check if the corresponding user is an admin*/
/*redirect to https://my-app.com/adminpage/ if user is an admin, otherwise, redirect to https://my-app.com/login/ */
} else {
/*user is signed-off, redirect to https://my-app.com/login */
}
}
</script>
I'm keeping this as the last option as it doesn't look like a very good flow.
Here's how my uiConfig looks right now:
var uiConfig = {
signInSuccessUrl: '/adminpage/',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID
]
}
The Crux is that I want to render my admin home page only if I know beforehand that the user is logged in and is an admin.
I want to know if there is a way to pass the ID token as a basic auth header when redirecting to the signInSuccessUrl from the firebaseUI page, or if the idea of sending an ID token itself is not necessary and there is an alternate better flow.
I think you're on the right track. I've been struggling to find something elegant to do this as well, but I ended up doing what you did. Ideally I wish signInSuccessUrl passed the jwt payload, therefore, my backend server could verify its authenticity, and I can then look up the user and then set the session or reject the session.
A lot of the API's and docs are written in the context of a "Firebase first" or "Firebase only" so you have to start getting creative integrating with a traditional REST API.
My context is somewhat similar. I'm a mobile-only app that used Firebase auth to offload auth, in exchange, it then linked to my own custom token. Recently I needed to make a few web properties and wanted to implement this same exchange for my own session management in a traditional client/server synchronous REST page.
window.initApp = function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
user.getIdToken().then(function(accessToken) {
redirectPost("/login", {"access_token": accessToken, "authenticity_token": $("meta[name='csrf-token']").attr('content')})
});
} else {
// User is signed out.
}
}, function(error) {
console.log(error);
});
};

How secure is firebase with auth?

I am not sure where to begin but I recently saw 'Firebase' while searching for no server database, while it seems interesting to me, I was little worried about putting my api codes directly in the js files, which obviously can be seen through source but I have read that you can change the read/write rules and need authentication. so I no longer worried about API after reading through some pages
but the main question is:
I wanted to create an admin portal for my page, so example my admin page is located in localhost/admin/ <<< The page will simply have a login form which is to access the portal, so everything is set
var config = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
};
firebase.initializeApp(config);
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
window.location = '/portal.html'
}
else {
// Do nothing
}
});
$("#loginbtn").click(function() {
var email = $('#login-name').val();
var password = $('#login-pass').val();
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
});
});
So when I log in successfully it will redirect me to that page but can someone just look through source code and then go that page manually and enter it?
Or even if I intend to build one page application and decide to change the page state after login, whatever functions i'm going to do after that, can someone still find out and inject the code ?
I'm not really expert on this but this what I was thinking before starting my project, so is there is any other way around?
If you want to add admin capabilities and you are using Firebase real-time database, you need to set some custom Firebase rules to only allow admins to access restricted data. So if a non-admin user signs in, they are unable to modify/access admin only data.
One way to do this with Firebase rules is to have a /whitelist node with uid1: "bojeil#bla.com", uid2: "puf#bla.com" for storing all whitelisted admin UIDs and then a top-level security rule for restricted admin only nodes like ".write": "auth != null && root.child('whitelist').child(auth.uid).exists()". It's fairly simple, but goes a long way.
If you are not using real-time database and building a traditional web application, you need to protect restricted admin only resources. You will need to send the Firebase ID token to your backend. You can do that by setting a session cookie with its value and making sure to update that session cookie every hour or so when the Firebase ID token is refreshed. When the cookie is sent with your request, you check for it, decode it (you can use the Firebase Admin SDKs for that) and check that the user it belongs to is an admin. If so, you can allow access, otherwise you block access. On every page, you would add an onAuthStateChanged listener. If that triggers with null, you redirect to the sign-in page. If the session cookie contains an ID token for a non-admin, you can do a HTTP redirect on your server to the user non-admin section.
tldr; you need to enforce the check on your backend by sending the Firebase ID token with the request and double checking its user has adequate privileges.

Delete a specific user from Firebase

Is there a way I can get a specific user account from firebase and then delete it?
For instance:
// I need a means of getting a specific auth user.
var user = firebase.auth().getUser(uid);
// Note the getUser function is not an actual function.
After, I want to delete that user and their additional data:
// This works
user.delete().then(function() {
// User deleted.
var ref = firebase.database().ref(
"users/".concat(user.uid, "/")
);
ref.remove();
});
Firebase Documentation states that users can be deleted if they are currently logged in:
firebase.auth().currentUser.delete()
My aim is to allow logged in admin user to delete other users from the system.
When using the client-side SDKs for Firebase Authentication, you can only delete the user account that is currently signed in. Anything else would be a huge security risk, as it would allow users of your app to delete each other's account.
The Admin SDKs for Firebase Authentication are designed to be used in a trusted environment, such as your development machine, a server that you control, or Cloud Functions. Because they run in a trusted environment, they can perform certain operations that the client-side SDKs can't perform, such as deleting user accounts by simply knowing their UID.
Also see:
delete firebase authenticated user from web application
Another common approach is to keep a allowlist/blocklist in for example the Firebase Database and authorize user based on that. See How to disable Signup in Firebase 3.x
I know this is an old question, but I found another solution to this.
You definitely don't want to use firebase-admin in your application itself, as I think was suggested by Ali Haider, since it needs a private key which you don't want to deploy with your code.
You can however create a Cloud Function in Firebase that triggers on the deletion of a user in your Firestore or Realtime database and let that Cloud Function use firebase-admin to delete the user.
In my case I have a collection of users in my Firestore with the same userid's as created by Firebase Auth, in which I save extra user data like the name and the role etc.
If you're using Firestore as me, you can do the following. If you're using Realtime database, just look up in the documentation how to use a trigger for that.
Make sure your Firebase project has cloud functions initialized. There should be a folder named 'functions' in your project directory. If not: initialize Cloud Functions for your project with the following command: firebase init functions.
Obtain a private key for your service account in the Firebase Console on the following page: Settings > Service accounts.
Place the json-file containing the private key in the functions\src folder next to the index.ts file.
Export the following function in index.ts:
export const removeUser = functions.firestore.document("/users/{uid}")
.onDelete((snapshot, context) => {
const serviceAccount = require('path/to/serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://<DATABASE_NAME>>.firebaseio.com"
});
return admin.auth().deleteUser(context.params.uid);
});
Now deploy your Cloud Function with the command firebase deploy --only functions
When a user is deleted in your Firebase Firestore, this code will run and also delete the user from Firebase Auth.
For more information on Firebase Cloud Functions, see https://firebase.google.com/docs/functions/get-started
Just apply this code same way that you have done authentication.
var user = firebase.auth().currentUser;
user.delete().then(function() {
// User deleted.
}).catch(function(error) {
// An error happened.
});
Using the Javascript API (not the admin SDK)
Like this answer points out for user sign in, a second app must be created to be able to delete another user than the one logged in.
This is how I did it:
async deleteUser (user) {
// Need to create a second app to delete another user in Firebase auth list than the logged in one.
// https://stackoverflow.com/a/38013551/2012407
const secondaryApp = firebase.initializeApp(config, 'Secondary')
if (!user.email || !user.password) {
return console.warn('Missing email or password to delete the user.')
}
await secondaryApp.auth().signInWithEmailAndPassword(user.email, user.password)
.then(() => {
const userInFirebaseAuth = secondaryApp.auth().currentUser
userInFirebaseAuth.delete() // Delete the user in Firebase auth list (has to be logged in).
secondaryApp.auth().signOut()
secondaryApp.delete()
// Then you can delete the user from the users collection if you have one.
})
}
In my opinion, you can delete specific user without Firebase Admin SDK. You must to storage Username, Password of accounts you want to manage. And login with account - you declare a admin account. After that just follow steps: using firebase auth to logout -> using firebase auth to login with account you want to delete -> using firebase auth to delete that account -> using firebase auth to logout -> login again with that "admin account". Hope this solution help you to delete accounts without using Firebase Admin SDK

Categories