Retrieving firebase data from ESP32 using micropython with authentication - firebase-realtime-database

I'm trying to connect to my realtime database from firebase using MicroPython in a ESP32, I was able to retrieve the data using ufirebase but only if the rules were public for reading and writing, now I have the following rules for the database:
{
"rules": {
".read": "auth.uid === <My uid>",
".write": "auth.uid === <My uid>"
}
}
I am able to get my uid from my email and password that were registered in the authentication section in firebase using the micropython-firebase-auth library, but now I am not able of doing the request using ufirebase, I have tried doing a request with urequests in the following way:
import urequests
def get_data():
response = urequests.get("https://<DATABASE_NAME>.firebaseio.com/<NODE>.json?auth=<My uid>")
data = response.json()
return data
But doing so, shows me the following message:
{'error': 'Permission denied'}
So I haven't been able of retrieving the information with the applied set of rules, the structure of the data is the following for all of the database.
Example of data to retrieve from the realtime database
Does anyone know how to do a request with micropython once you got the uid?

You can't authentication by just passing your UID to the database. That'd be a huge security risk, as the UID is not a secret. You'll instead need to pass the user's ID token, which amongst others includes their UID, as shown in the documentation on authenticating REST requests.
If your microcontroller runs in a trusted environment, consider using the Admin SDK as shown here: How to authenticate to Firebase using Python?.
If the device should be considered untrusted, there is no Firebase SDK for client-side Python to generate such a token though. Your options in that case are to either call the REST API to authenticate the user, or use a 3rd party wrapper such as Pyrebase to sign in

Related

Why need front end stores firebase token?

I am making a web application. Front side is react, server side is rails api and I use firebase authentication.
Now, I get firebase token and set authorization header whenever calling rails api as below.
client.interceptors.request.use(
async (config) => {
config.headers['Content-type'] = 'application/json'
config.withCredentials = true
var token = await firebaseApp.auth().currentUser?.getIdToken()
config.headers['Authorization'] = `Bearer ${token}`
return config
},
(error: AxiosError) => {
throw new Error(error.message)
}
)
But, I found some ways to store token, unsafe local storage, http only cookie.
Why need front end stores firebase token? Is it bad to get the token every time calling rails api?
Firebase ID Tokens are basically JWT, signed by Firebase.
Now imagine a scenario where you need to identify the user in your server. You will probably pass the user's UID in the HTTP Request, which is not safe as that can be easily bruteforced unless you have some sort of rate limiting in your server.
What I meant by signed?
A JWT looks something like: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The data stored in above JWT is:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
You need to verify those Firebase IDTokens using Firebase Admin SDK. I don't know if that works with Ruby but worth checking the link above.
Verifying those will either return an object with user auth info or an error if that is an invalid JWT.
You must always pass this JWT in you REST requests to your server because these cannot be bruteforced. Anyone can make a JWT (IDToken) with same content but they don't know your signature. They will need your Firebase Service Account credentials to do so.
Also, JWTs expire eventually (I assume after an hour). So it's not bad to get token again and again. That's what they are meant for. Short term access.
I recommend you to watch this JWT Tutorial.
Just be sure to pass the idToken to your REST API to authenticate users and not their UID.

Getting full access to DynamoDB from my ios app using AWS Cognito Developer Identities

I have implemented a AWS Lambda function and used the gateway to return the fulling data:
var param =
{
IdentityPoolId: "actualIdentityPoolId",
Logins: {} // To have provider name in a variable
};
param.Logins["com.testing.userLogin"] = userId;
cognitoidentity.getOpenIdTokenForDeveloperIdentity(param,
function(err, data)
{
if (err) return fn(err); // an error occurred
else fn(null, data.IdentityId, data.Token); // successful response
});
So the identityId and token get sent back to the ios device. In my device I try to connect to an AWS DynamoDB table but access is denied. How do I use the identityId and token to gain access to the tables?
I have set up roles in IAM for Unauth which denies Dydnamo and Auth which gives access to the tables through its policies.
I am trying to implement authentication using: http://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html
I see there are two flows which are Basic and Enhanced. The documentation says most users will use the enhanced flow and that implements GetCredentialForIdentity.
How is that implemented in my ios code so that I can switch my role from unauth to auth and can access to dynamodb? How long will this access last? I would like to do this all in my ios code instead of using lambda or something else like that.
If your user is unauthenticated, then logs in you need to clear your credentials, and your 'logins' method should now return a properly updated logins map.
Here is the documentation to help you:
http://docs.aws.amazon.com/cognito/latest/developerguide/developer-authenticated-identities.html
Double check your DynanoDB Roles for authenticated access your DynamoDB resource. An example role for this are on the following page of the developer guide you referenced. The page is called "IAM Roles" and the last section is the important one: "Fine-Grained Access to Amazon DynamoDB".
Stick with your plan to use the Enhanced Authflow. It is recommended and makes less calls to authenticate (your users will appreciate this). Just make sure you mobile clients call GetCredentialsForIdentity from iOS.
From the Enhanced Authflow documentation further down your page:
The GetCredentialsForIdentity API can be called after you establish an identity ID. This API is functionally equivalent to calling GetOpenIdToken followed by AssumeRoleWithWebIdentity.
The AssumeRoleWithWebIdentity is the important piece that allows your user to assume the Role that gets access to the DynamoDB resource. Cognito will take care of the rest as long as you set up the Roles correctly within the Cognito console:
In order for Amazon Cognito to call AssumeRoleWithWebIdentity on your behalf, your identity pool must have IAM roles associated with it. You can do this via the Amazon Cognito Console or manually via the SetIdentityPoolRoles operation (see the API reference)

Where to get analytics reporting realtime v3 API KEY?

spend about 4 hours but can not find where to get the key for this GET
https://www.googleapis.com/analytics/v3/data/realtime?ids=ga*****&metrics=rt%3AactiveUsers&**key={YOUR_API_KEY}**
Have tried different api keys from here https://console.developers.google.com/apis/credentials/key/
but no one is working.
Always got this result
{
"error":{
"errors":[
{
"domain":"global",
"reason":"required",
"message":"Login Required",
"locationType":"header",
"location":"Authorization"
}
],
"code":401,
"message":"Login Required"
}
}
Login Required
Means that you don't have access to do what you are trying to do.
The Google Analytics Real-time API is actually a private API. This means that the data within is Private user data. For private user data you need to use an access token to access it. Only public APIs can be accessed using an API key.
So "Key=" will not work you need to use "access_token=" access token must be a valid authenticated access token. Not the API key from Google Developers console. This is why you are seeing the : Login Required error message you need access.
In order to get an access token you must be authorized Real Time Reporting API - Authorization
Note: The Real Time Reporting API, in limited beta, is available for developer preview only. Sign up to access the API.

Firebase 3: Server authentication in iOS

In the old Firebase, I used to be able to authenticate in iOS using the server method in which a secret is generated on Firebase website and signInWithCustomToken is used to sign in with full admin privilege.
Can this still be done with the new Firebase? I can't seem to find a way to. The same function and secret would return this error:
Error Domain=FIRAuthErrorDomain Code=17000 "The custom token format is incorrect..."

Proper method of getting a server auth access token for a client to use with google analytics

I have a global account that has several views that I want to use on the server side to embed dashboards for the various views on the client side. From what I understand, I get an access token using a service account on the server side and can then send the access token to the client side whenever needed. I was wondering, is this the correct flow? Should the access token be per session?
The authorization on the client side shown here has a field for a server auth access token, but couldn't find documentation on the exact flow I wanted. Basically I'm unsure what the proper way of generating that server auth access token is. Any help/pointers would be very much appreciated.
[Here][1] is an example of how to set up server side auth. The above code creates a new token when anyone visits the site. You can see the endpoint that gets that access token [here][2].
Below are the general steps to get to a working version:
Step 1: Create a service account and download the JSON key
Step 2: Add the service account as a user in Google Analytics
Step 3: Use the JSON key data to request an access token
# service-account.py
import json
from oauth2client.client import SignedJwtAssertionCredentials
# The scope for the OAuth2 request.
SCOPE = 'https://www.googleapis.com/auth/analytics.readonly'
# The location of the key file with the key data.
KEY_FILEPATH = 'path/to/json-key.json'
# Load the key file's private data.
with open(KEY_FILEPATH) as key_file:
_key_data = json.load(key_file)
# Construct a credentials objects from the key data and OAuth2 scope.
_credentials = SignedJwtAssertionCredentials(
_key_data['client_email'], _key_data['private_key'], SCOPE)
# Defines a method to get an access token from the credentials object.
# The access token is automatically refreshed if it has expired.
def get_access_token():
return _credentials.get_access_token().access_token
Back to the client side:
Step 4: Load the Embed API library.
<script>
(function(w,d,s,g,js,fs){
g=w.gapi||(w.gapi={});g.analytics={q:[],ready:function(f){this.q.push(f);}};
js=d.createElement(s);fs=d.getElementsByTagName(s)[0];
js.src='https://apis.google.com/js/platform.js';
fs.parentNode.insertBefore(js,fs);js.onload=function(){g.load('analytics');};
}(window,document,'script'));
</script>
Step 5: Add HTML containers to host the dashboard components.
<div id="chart-1-container"></div>
<div id="chart-2-container"></div>
Step 6: Write the dashboard code.
Use the access token obtained in step 3 to authorize the Embed API.
gapi.analytics.ready(function() {
/**
* Authorize the user with an access token obtained server side.
*/
gapi.analytics.auth.authorize({
'serverAuth': {
'access_token': '{{ ACCESS_TOKEN_FROM_SERVICE_ACCOUNT }}'
}
});
...
The additional work of creating an endpoint which returns the token depends on your back end implementation but the source code of how the demo does it can be found [here][2].
[1]: https://ga-dev-tools.appspot.com/embed-api/server-side-authorization/
[2]: https://github.com/googleanalytics/ga-dev-tools/blob/abb3c5a18160327a38bf5c7f07437dc402569cac/lib/controllers/server_side_auth.py
I'm not very familiar with Google Analytics, but as far as OAuth goes, the handling of access tokens and refresh tokens should all be on the server-side. The client receives an authorization code and provides that to the server, which then obtains the tokens and uses the tokens to obtain the data necessary. There shouldn't be any need to send an access token to the client.
It might be helpful to read this, which describes the standard OAuth flow:
https://developers.google.com/identity/protocols/OAuth2

Resources