PERMISSION DENIED (grpc_status :7) when accessing Firestore - firebase

I'm having some trouble accessing my firestore data via the python API. I've tried all the solutions that are mentioned in the other answers, but I still keep getting the same permission denied issue:
_InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
status = StatusCode.PERMISSION_DENIED
details = "Missing or insufficient permissions."
debug_error_string = "{"created":"#1636057424.408000000","description":"Error received from peer ipv4:x:x:x:x:443","file":"src/core/lib/surface/call.cc","file_line":1068,"grpc_message":"Missing or insufficient permissions.","grpc_status":7}"
>
Here's how I'm using the API:
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
cred = credentials.Certificate('/users/88232/cred.json') #correct credentials path - also tried pasting the dictionary directly
firebase_admin.initialize_app(cred)
db = firestore.Client('myapp') #made sure it's the right project's name (I have multiple projects)
doc_ref = db.collection(u'sample').document(u'0SZxt2xXs7n8Vglz8wEu')
doc = doc_ref.get() #error here
Things I've tried:
Use the service account credentials from firebase console in the API [1]
Include data store owner as part of roles when creating a new service account and using these credentials in the API [2]
Made sure Rules say allow read, write: if true; [3]
I'm not sure what else to try. Can someone please let me know if I have missed something?

I figured it out. Apparently, the issue was in this line:
db = firestore.Client('myapp')
if I change this to:
db = firestore.client()
everything works just as expected.
This is also the only method shown in Google's official docs (https://firebase.google.com/docs/reference/admin/python/firebase_admin.firestore).
I'm not sure what guide/walkthrough I followed that made me use Client instead of client but I'm not able to figure out the difference. If anyone knows, please comment below.

Related

Custom logging from firebase function

I'm trying to follow this guide to put some custom logging into a firebase function. The function itself is running, and I can see the data being passed in (it's an https 'callable' function). But as soon as it hits the line where it tries to actually write that log entry, I get "Error: 7 PERMISSION_DENIED"
Since the console.log() calls write to the cloud logs, I'd assumed the firebase function has access to Cloud Logging. But perhaps it needs additional permission? I can't find any reference to where this should be set on that page though.
// Logging, logName, region, functions are provided by the surrounding app
const logging = new Logging()
const log = logging.log(logName)
const METADATA = {
resource: {
type: 'cloud_function',
labels: {
function_name: 'CustomLog',
region
}
}
};
exports = module.exports = functions.https.onCall(async data => {
const exVersion = 6
const exId = data.exId
console.log('***** exVersion:', exVersion, 'exId:', exId) // exId from caller
const entry = log.entry(METADATA, data.error) // data.error from caller
console.log('METADATA:', METADATA) // Shows in Logs Explorer
console.log('entry:', entry) // Shows in Logs Explorer
log.write(entry) // Results in Error: 7 PERMISSION_DENIED
return {
exVersion,
exId,
}
})
If I run it from the CLI using firebase function:shell, the log entry is created correctly, so I'm pretty confident the code is correct.
OK, I finally tracked it down. According to this answer, the service account used by firebase functions is {project-id}#appspot.gserviceaccount.com, and in my project, that account did not have the 'Logs Writer' role. Adding that role solves the problem.
I find it odd that the firebase functions don't need that role to log messages using console.log(), but perhaps that call is intercepted by the functions environment, and the logs are written as a different service account. It also explains why the functions running locally were able to write the logs, as they run using the 'owner' service account, which has full access.
According to the Firebase documentation page you have linked:
The recommended solution for logging from a function is to use the
logger SDK. You can instead use standard JavaScript logging calls such
as console.log and console.error, but you first need to require a
special module to patch the standard methods to work correctly:
require("firebase-functions/lib/logger/compat");
Once you have required the logger compatibility module, you can use console.log() methods as normal in your code.
Thus you might to require this library, however I am not sure this is producing your "Error: 7 PERMISSION_DENIED error, but you might also try some solutions that have worked for some members of the community.
Perhaps the logging API is not enabled in your project. You'll get a permission denied error when attempting to use it in that case.
It's a couple levels in, but the guide you linked points to
https://github.com/googleapis/nodejs-logging#before-you-begin, which includes a step to "Enable the Cloud Logging API"

Firebase Realtime Database - how to manage database rules using REST API

I would like to get/set realtime database rules using Rest API however no tutorial is working for me. I try to do it like that:
I copied the url to my realtime database which is in Europe https://my-project-database.europe-west1.firebasedatabase.app/
I copied the java code from this tutorial: https://firebase.google.com/docs/database/rest/auth which was supposed to give me the access token
val googleCred = GoogleCredential.fromStream(File("/path/to/my/key.json").inputStream())
val scoped = googleCred.createScoped(
Arrays.asList( // or use firebase.database.readonly for read-only access
"https://www.googleapis.com/auth/firebase.database",
"https://www.googleapis.com/auth/userinfo.email"
)
)
scoped.refreshToken()
val token = scoped.accessToken
println(token)
However the token looks very strange with a long string of dots at the end like (it's related to: Why am I getting a JWT with a bunch of periods/dots back from Google OAuth?)
ya29.c.Kp8BCgi0lxWtUt-_[Normal JWT stuff, redacted for
security]yVvGk...............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
I did HTTP GET to address like https://my-project-database.europe-west1.firebasedatabase.app/.settings/rules.json?access_token=$token and I got 401 UNAUTHORIZED
I assume it's due to the fact that I use the whole of this strange token full of dots as the access_token variable. So now I have questions how to transform it and use as the access_token to make it work
EDIT:
I created this gist although it's in python it has exactly the same problem. How to make it work ?
https://gist.github.com/solveretur/86d53a9c0221f096c38c3ef8f70a8dbd
It works I used wrong database key

Getting "Missing or malformed Token" while using gofiber firebase-auth

I am trying to run Gofiber firebase-auth. I have generated a private key from Firebase Console, Settings -> Service Account -> Generate new private key and have given the file path to:
.env:
GOOGLE_SERVICE_ACCOUNT = 'C:/Users/Desktop/flutter-demo.json'
WEB_API_KEY = "<API_KEY>" // from config section of general settings at firebase console
TEST_USER_EMAIL = "test#test.com"
TEST_USER_PASSWORD = "test123"
which is used in main.go:
serviceAccount, fileExi := os.LookupEnv("GOOGLE_SERVICE_ACCOUNT")
opt := option.WithCredentialsFile(serviceAccount)
But, on accessing any of the Authenticated Routes, I'm getting:
Missing or malformed Token
Can anyone please help, maybe I'm doing some mistake or missing something from the docs
Hi below is an example of using gofiber firebase auth,
https://github.com/gofiber/recipes/tree/master/firebase-auth
Hope this will help you. Thanks
Thanks to Sachintha, one needs to send an Authorization Header token from login with the user name and password, as go firebase auth just a middleware to check whether endpoints are authenticated and it does not provide any authentication or user login.

Microsoft Graph API - error 403 "Insufficient privileges to complete the operation"

I'm trying to use the AzureR family of R packages to interact with Outlook through the Graph API. Using Microsoft365R I have the following code:
outl <- get_business_outlook(
tenant = tenant_id,
app = client_id,
password = client_secret
)
But this results in a 403 error:
Error in process_response(res, match.arg(http_status_handler), simplify) :
Forbidden (HTTP 403). Failed to complete operation. Message:
Insufficient privileges to complete the operation.
The app in question has the API permissions Mail.ReadWrite, Mail.ReadWriteShared, Mail.Send, Mail.Send.Shared, offline_access, openid, User.Read.
I also tried using the AzureGraph package directly like:
login <- create_graph_login(
tenant = tenant_id,
app = client_id,
password = client_secret
)
This works and I get a token. I then try to extract user information with me <- login$get_user(), but this throws the same 403 error as above. I suspect there is something I need to do to actually authenticate the user, but I can't really figure out what.
I am entirely new to the Graph API so it's very possible that I have missed something obvious. Any help appreciated!
Microsoft365R/AzureGraph author here. In the code you show, both with get_business_onedrive() and create_graph_login(), you are authenticating as the app, not as the user. This means that there is no user account involved, hence you're unable to view user details or send email.
To authenticate as the user, run
# Microsoft365R
get_business_outlook("tenant_id", app="client_id")
# AzureGraph
create_graph_login("tenant_id", app="client_id")
ie, without the password argument. You should know it's working if R opens up a browser window for you to login to Azure (or to show it's successfully logged in).
The latest revision of the AzureAuth package has a vignette that explains a bit more on the various authentication scenarios. AzureAuth::get_azure_token is the underlying function used to obtain an OAuth token by Microsoft365R and AzureGraph, and you can pass down the arguments mentioned in the vignette from get_business_outlook and create_graph_login.

Send firebase storage authorization as url parameter from a flutter web app

I would like to know how to make an authorized request to firebase storage using the user Id Token as a parameter in the url. Right now with a firebase rule of 'request.auth != null' I receive a 403 network error (Failed to load video: You do not have permission to access the requested resource). Here is my GET request url:
https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media&auth=eyJh...<ID TOKEN>...Ll2un8ng
-WITHOUT the firebase rule in place I'm able to successfully get the asset with this request url https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media
-also tried token=, token_id=, tokenId=
-the reason for not using the firebase SDK to fetch the file is so that I can use the flutter video_player (https://pub.dev/packages/video_player#-example-tab-) package and use this with files in firebase, I mention this in case theres a better way to use the video_player library in flutter web right now:
_controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
closedCaptionFile: _loadCaptions(),
);
[EDIT] It appears that it's not possible to pass the auth in as a query parameter. After some exploring, I found an acceptable way to still use the video_player with your firebase assets that are protected (If you're not using rules to protect them, you can directly use the firebase url). I will post some general steps here and some sample code:
Use the Storage Firebase SDK package to get the Uint8List, the uri given by getDownloadURL has the correct header auth, for example
import 'package:firebase/firebase.dart';
final url = await storagePath.getDownloadURL();
final response = await http.get(url);
if (response.statusCode == 200) {
return response.bodyBytes;
}
use the Uint8List buffer to init a Blob object which you'll use to then create an ObjectURL which basically gives you the same interface as a file url to use as the network url for your video player
final blob = html.Blob([data.buffer], 'video/mp4');
final videoUrl = html.Url.createObjectUrl(blob);
videoPlayerController = VideoPlayerController.network(
videoUrl)
..initialize().then((_) {...
That's it.
Firebase Storage REST does not (rightly) support authorization from GET query string as you are trying to do. Instead, it uses the standard Authorization header (see here).
Firebase cloud storage internally uses Google Cloud Storage. Mentioned here
If the library you use doesn't support HTTP headers yet, you must consider an alternative. The issue you mentioned in the comment shows that the feature is still under development, so you can also wait for the library to come out with the support for headers.
Internally all this package does for flutter-web is create an HtmlElementView widget here for which it passes a VideoElement (ref here) from the package dart:html with the provided URL which translates to a <Video> tag inside a shadow dom element in your web page. The error 403 could also mean you are trying to access it from a different origin.
I would suggest following approach.
Check your console for any CORS related errors. If yes, then you will have to whitelist your ip/domain in the firebase storage. Check this post for possible approach and more details here.
Check if you are able to access the URL directly with the authorization token as a query parameter as you suggested. If not then, it is not the correct way to access the object and should be corrected. You could update the question with the exact error details.

Resources