Firebase Cloud Firestore REST api authentication with only WEB API key? - firebase

I'm trying to insert a new record in a Firebase Cloud Firestore database via its REST API and curl.
Reading from the database is working as expected since the operation is public. Create operation is not listed in the database rules and it is performed only server side, but I'm unable to do it using only the project API KEY.
Take for example the following curl request:
curl --header "Content-Type: application/json" \
--request POST \
--data '{"fields":{"myField": {"stringValue": "test"}}}' \
https://firestore.googleapis.com/v1/projects/**MY_PROJECT**/databases/\(default\)/documents/**MY_COLLECTION**?key=**MY_KEY**
The above request returns "403: Missing or insufficient permissions.". The provided api key is fetched from the Firebase project's settings -> Web API key.
Am I missing something or authentication via only API keys is not possible?
p.s. I forgot to mention that the API KEY is unrestricted in the GCP dashboard.

The Firestore REST API doesn't support passing API keys. You'll notice that in the documentation, there is no mention of a "key" parameter.
If you want to perform authenticated operations using the REST API, you'll have to follow the documentation on authentication and authorization. To summarize:
For authentication, the Cloud Firestore REST API accepts either a
Firebase Authentication ID token or a Google Identity OAuth 2.0 token.
The token you provide affects your request's authorization:
Use Firebase ID tokens to authenticate requests from your application's users. For these requests, Cloud Firestore uses Cloud
Firestore Security Rules to determine if a request is authorized.
Use a Google Identity OAuth 2.0 token and a service account to authenticate requests from your application, such as requests for
database administration. For these requests, Cloud Firestore uses
Cloud Identity and Access Management (IAM) to determine if a request
is authorized.

Related

Is there a way to connect Firestore Database through REST API without using Auth 2.0 authentication

I am trying to follow this documentation to get my firestore collections and documents in postman.
When I send this request
curl --location --request GET 'https://firestore.googleapis.com/v1/projects/{project-id}/databases/(default)/documents/{document-id}'
I get an empty object.
My challenge is I have failed to get the access token without implementing the sign with the feature.

Authenticate at Google Cloud Storage JSON API with Firebase ID token

I have a mobile app (Android/iOS) that uses the Firebase SDK for several Firebase services (including Authentication and Storage).
Now there's a subsystem within the app that can't directly access the Firebase SDK, but I need to upload files to Storage from this subsystem. HTTP(S) requests are possible, so I tried to use the Storage JSON API for uploading.
However, an OAuth 2.0 token is required for authorizing requests via the JSON API. Is there a simple way to receive such a token, when there's already a signed-in user in the Firebase SDK? It seems the only thing I get from the Firebase SDK is the "Firebase ID token" (JWT token), but I don't know how to convert it (or if this is even possible) to an accepted OAuth token for the JSON API.
I think you're trying to do the petition from the plugin itself and it might not have the permissions.
Did you pass it to sign In With Custom Token to the SDK when your users sing-in?
I read that after that, a Custom Token and credentials are attached to the user's profile.
Why don't you try to do the petition from the user's profile instead of doing it from the plugin?

How to authenticate a Firebase user to an IFTTT service?

I'm trying to build an IFTTT service and connect it to my Firebase backend.
I need to authenticate user as indicated in the IFTTT docs:
https://platform.ifttt.com/docs/api_reference#service-authentication
IFTTT’s protocol supports OAuth2 authentication, including support for
refresh tokens if so desired.
Your service API should use access tokens for authentication and as a
source of identity. A single access token should correspond to a
single user account or resource owner on your service.
If refresh tokens are used, they must be non-expiring. If refresh
tokens are not used, access tokens must be non-expiring.
But I can only get short-lived access tokens from Firebase it seems. Where can I get or how can I generate such tokens from the Firebase auth SDK?
Update in response to #FrankvanPuffelen:
I'll create an IFTTT service running on a Node server (possibly simply Cloud Functions) that will use the Firebase RTDB to send formatted HTTP request back to IFTTT. IFTTT requires me to authorize user accounts. Their required UX is something like this:
If an IFTTT user tries to use my service on the IFTTT website,
an auth dialog for my service pops up.
The user logs in and confirms IFTTT's access to their data on my service.
Some OAuth 2.0 tokens are exchanged.
IFTTT servers will periodically send requests (authentified with those tokens) on behalf of the user to my server.
Part of the question is: Can I use the Firebase Auth API to get those tokens, etc. or do I need to create a new OAuth 2.0 "layer" with my own generated tokens for IFTTT?
PS: I'm very new to OAuth, so it's all a bit confusing to me, sorry if the question isn't very clear.
So IFTTT calls Cloud Functions, which then calls Realtime Database, and you want to authentication the IFTT user with Realtime Database. Is that correct? If so, you can either use an OAuth2 token or create a Firebase Authentication session cookie.
Use an OAuth2 token
I did this not too long ago for accessing the Realtime Database from Google Apps Script. The requirements are relatively simple (once you know them):
The OAuth2 tokens must be requested with the correct scopes: https://www.googleapis.com/auth/userinfo.email and https://www.googleapis.com/auth/firebase.database.
The OAuth2 access token must be present in the request to Realtime Database.
The authenticated user must be at least an editor on the Firebase project. Note that this is not a Firebase Authentication user, but a Google user account.
Also see:
How to integrate Firebase into Google Apps Script without using (deprecated) database secret
Use a Firebase Authentication session cookie
You can also use a Firebase Authentication session cookie, which can be longer-lived (up to 2 weeks) than a regular Firebase Authentication ID token (up to an hour). You'll want to set up a Cloud Function for creating the session cookie, call that from IFTTT, and then pass the session cookie with the IFTTT request and along to the Realtime Database.
For more on this, see:
the Firebase documentation on managing session cookies.
I'm posting my solution here, this is a rough draft of what I did at at the time.
I'm using this auth method: My API has users with non-expiring OAuth2 access tokens and have an Express server responding at a Firebase HTTPS Cloud Function endpoint. Currently, at the prototyping stage, it generates fake tokens from the UID that are successfully accepted by IFTTT.
It's a redirect-heavy authentification flow based on this old IFTTT api example: https://github.com/IFTTT/connect_with_ifttt_auth_sample
Here's the gist of it:
Tokens and Auth Codes are just randomized and encrypted UIDs for now.
/oauth/authorize redirects to my app.
The app asks the user if they want to authorize IFTTT
The app redirects to /oauth/authorize_user
/oauth/authorize_user generates a user-specific code and redirects the user to IFTTT with this code
IFTTT asks /oauth/token to exchange the code for a Bearer tokens.
IFTTT can now make requests on behalf of this user with this bearer token.
Sample code here: https://gist.github.com/nathanvogel/15ed311258b91d7ec3d25f44047780e2

Firebase CREDENTIAL for rest API

Firebase Rest API mentions that we can pass CREDENTIAL to provide access to authenticated nodes. However I was not able to find documentation on where I can find these credential or generate these credential. Custom tokens generated using NodeJS firebase-admin client also don't work.
https://firebase.google.com/docs/database/rest/save-data
https://docs-examples.firebaseio.com/rest/saving-data/auth-example.json?auth=CREDENTIAL
If you scrolled down a little on the same page, you would find the answer:
In the following example we send a POST request with an auth parameter, where CREDENTIAL is either our Firebase app secret or an authentication token...
Firebase secrets are legacy credentials you can find/create under Project settings - Service Accounts in the Console. Using one as the auth parameter gives the caller administrative access.
Or you can use a service account to generate admin level access tokens instead of relying on the legacy secrets. See here for the Java implementation.
Or if you have an authenticated user – for example you're implementing an API a client apps call via HTTP, passing along their current access token –, you can use that token directly to impersonate the user.
The custom authentication tokens serve a completely different purpose and are part of a different sign in flow. Therefore they do nothing via the REST API.

AWS API Gateway security

I am playing around with Amazon Gateway API and am struggling to get my head around security.
Obviosuly the API I create cannot be accessed by anyone and needs to be secured. Amazon suggest using API keys or IAM roles. I have a few questions:
How can i authenticate my client requests so that my app and only my app can make use of the API?
How does AWS determine a role for an incoming request?
If I choose API key approach, how does it work?
Thanks!
How can i authenticate my client requests so that my app and only my app can make use of the API?
If your backend is a Lambda function, you can grant permission to API Gateway to access it.
If your backend is a HTTP backend, you will have to find out the authenticate strategy at your HTTP backend side.
How does AWS determine a role for an incoming request?
If your API is required IAM auth, the incoming request has been signed with AWS sigV4 algorithm. AWS is able to determine the permission of the credential is used to sign the request.
If I choose API key approach, how does it work?
All the incoming requests have to contain the API key in the header. If the key is allowed to access the API, the request will be processed, otherwise it will return 403.

Resources