Authentication with firestore in python using firebase_admin - python

I am using firestore in python with firebase_admin and want to access the authentication module of firebase. I have created data in authentication with auth.create_user() by importing auth from firebase_admin.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore, auth
cred = credentials.Certificate("servicesAccountKey.json")
firebase_admin.initialize_app(cred)
db = firestore.client()
# <<<<<<<<<<<<<<<<<<<<******************** SignUp ********************>>>>>>>>>>>>>>>>>>>>
def signUp(userObject):
user = userObject.getUser()
auth.create_user(uid=user['cnic'], email=user['email'], password=user['password']) "
Now I want to authenticate for signIn but not able to find module auth.sign_in_with_email_and_password. This module is available with realtime database which connects with pyerbase but not in firestore connected with firebase_admin.
def signIn(cnic,password):
auth.sign_in_with_email_and_password(cnic, password)
I can use auth with pyrebase but i have to import pyrebase and firebase_admin both which i dont want it.
Is any module available for firebase_admin for authentication to signIN ?

The Admin SDKs for Firebase run with elevated, administrative privileges, and don't have any capability to sign in a user.
You may want to consider your use-case: if you ship the administrative credentials (that the Admin SDK needs/uses) to your regular users they have full access to your Firebase and Google Cloud project. You'll want to separate the administrative functionality of your app from the end-user functionality, and use either the REST SDK or a client-side SDK (like Pyrebase) for the end-user app.

Related

Firestore SDK hangs in production

I'm using the Firebase Admin Python SDK to read/write data to Firestore. I've created a service account with the necessary permissions and saved the credentials .json file in the source code (I know this isn't the most secure, but I want to get the thing running before fixing security issues). When testing the integration locally, it works flawlessly. But after deploying to GCP, where our service is hosted, calls to Firestore don't work properly and retry for a while before throwing 503 Deadline Exceeded errors. However, SSHing into a GKE pod and calling the SDK manually works without issues. It's just when the SDK is used in code flow that causes problems.
Our service runs in Google Kubernetes Engine in one project (call it Project A), but the Firestore database is in another project (call it project B). The service account that I'm trying to use is owned by Project B, so it should still be able to access the database even when it is being initialized from inside Project A.
Here's how I'm initiating the SDK:
from firebase_admin import get_app
from firebase_admin import initialize_app
from firebase_admin.credentials import Certificate
from firebase_admin.firestore import client
from google.api_core.exceptions import AlreadyExists
credentials = Certificate("/path/to/credentials.json")
try:
app = initialize_app(credential=credentials, name="app_name")
except ValueError:
app = get_app(name="app_name")
client = client(app=app)
Another wrinkle is that another part of our code is able to successfully use the same service account to produce Firebase Access Tokens. The successful code is:
import firebase_admin
from firebase_admin import auth as firebase_admin_auth
if "app_name" in firebase_admin._apps:
# Already initialized
app = firebase_admin.get_app(name="app_name")
else:
# Initialize
credentials = firebase_admin.credentials.Certificate("/path/to/credentials.json")
app = firebase_admin.initialize_app(credential=credentials, name="app_name")
firebase_token = firebase_admin_auth.create_custom_token(
uid="id-of-user",
developer_claims={"admin": is_admin, "site_slugs": read_write_site_slugs},
app=app,
)
Any help appreciated.
Turns out that the problem here was a conflict between gunicorn's gevents and the SDK's use of gRCP. Something related to websockets. I found the solution here. I added the following code to our Django app's settings:
import grpc.experimental.gevent as grpc_gevent
grpc_gevent.init_gevent()

Using firestore in colab with python

i'm trying to use firebase in colab with Python. But there is unsolvable error,
so i need some help.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
cred = credentials.Certificate('/content/myKey.json')
firebase_admin.initialize_app(cred) # error in this line
db = firestore.client()
ValueError: : The default Firebase app already exists. This means you called initialize_app() more than once without providing an app name as the second argument. In most cases you only need to call initialize_app() once. But if you do want to initialize multiple apps, pass a second argument to initialize_app() to give each app a unique name.
What can i do for solving this problem?
i also found similar answer with this, so i tried some many tips in there, like below.
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
if not firebase_admin._apps:
cred = credentials.Certificate('/content/foodle-94e80-firebase-adminsdk-zr21t- f02504e9fb.json')
firebase_admin.initialize_app(cred)
else:
app = firebase_admin.get_app()
db = firestore.client(app) # new error in this line
but new error is confusing me.
DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, please see https://cloud.google.com/docs/authentication/getting-started
What can i do?
Looks like there's a default instance of the Firebase app getting initialized somewhere. When the default instance gets created, it uses GOOGLE_APPLICATION_CREDENTIALS instead of the credentials you pass in manually.
You can either provide GOOGLE_APPLICATION_CREDENTIALS to the script, or ignore the default instance of the firebase app and create an explicitly named one.
To create an explicitly named app, change your code to provide a name:
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
cred = credentials.Certificate('/content/myKey.json')
firebase_admin.initialize_app(credential=cred, name='myApp')
db = firestore.client()
To provide GOOGLE_APPLICATION_CREDENTIALS and use the default app:
If you're running your python script from the console, you can provide a value for that by running
export GOOGLE_APPLICATION_CREDENTIALS='/content/myKey.json'
In colab, you need to add this to your script:
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"]="/content/myKey.json"
After this you can run your second example.
(To get the credentials JSON go to this page, select your firebase-adminsdk service account, click 'ADD KEY', 'Create new key', select JSON as your option and download the resulting file.)
In my case it worked with
cred = credentials.Certificate("/content/drive/My Drive/Colab Notebooks/LALALA.json")
firebase_admin.initialize_app(cred)

How to access Firebase Firestore from GCP Cloud Function

I am trying to access a Firebase Firestore DB from a GCP Cloud Function - the function is not part of the Firebase project - so two separate projects. When I config/init the DB I get a permissions error
def hello_world(request):
import firebase_admin
import flask
import json
from flask import request
from firebase_admin import credentials
from firebase_admin import firestore
try:
firebase_admin.initialize_app(options={
'apiKey': '<appkey>',
'authDomain': '<authdomain>',
'databaseURL': '<url>',
'projectId': '<projID>',
'storageBucket': '<bucket>',
'messagingSenderId': '<id>',
'appId': '<app ID>'
})
except:
print("DB already init")
#end db init
db = firestore.client()
# end db setup
I expect/want the result to be to initialize the DB so I can read/write to it, but I get an error:
Error: function crashed. Details:
403 Missing or insufficient permissions.
You seem to be using the app init settings for web, you need to use the sdk key instead. Go to Settings -> Services Account -> and generate your key.
Include the json file instead of those parameters. Hope this helps!

how do I get the project of a service account?

I'm using the python google.cloud api
For example using the metrics module
from google.cloud import monitoring
client = monitoring.Client()
client.query(my/gcp/metric, minutes=10)
For my GOOGLE_APPLICATION_CREDENTIALS im using a service account that has specific access to a gcp project.
Does google.cloud have any modules that can let me derive the project from the service account (like get what project the service account is in)?
This would be convenient because each service account only has access to a single project, so I could set my service account and be able to reference that project in code.
Not sure if this will work, you may need to tweak it:
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
credentials = GoogleCredentials.get_application_default()
service = discovery.build('yourservicename', credentials=credentials)
request = service.projects().list()[0]
Google Cloud Identity and Access Management (IAM) API has ‘serviceAccounts.get’ method and which shows the projects associated with a service account as shown here. You need to have proper permissions on the projects for the API to work.
The method google.auth.default return a tuple (project_id, credentials) if that information is available on the environment.
Also, the client object knows to which project it is linked from (either client.project or client.project_id, I'm not sure which one for the Monitoring API).
If you set the service account manually with the GOOGLE_APPLICATION_CREDENTIALS env var, you can open the file and load its json. One of the parameters in a service account key file is the project id.

403 error from Google Admin SDK with AppAssertionCredentials

I'm trying to list users via Google admin directory API.
import logging
import os
from google.appengine.api import memcache
from googleapiclient import discovery
from oauth2client.contrib.appengine import AppAssertionCredentials
import httplib2
from flask import Flask
credentials = AppAssertionCredentials(scope='https://www.googleapis.com/auth/admin.directory.user')
auth_http = credentials.authorize(httplib2.Http(cache=memcache))
service = discovery.build('admin', 'directory_v1', http=auth_http)
#app.route('/list')
def list():
results = service.users().list(domain='example.com', maxResults=10, orderBy='email').execute()
return 'success'
app = Flask(__name__)
I'm running this in App Engine and have enabled domain-wide delegation for App Engine default service account, as instructed in https://developers.google.com/api-client-library/python/auth/service-accounts
This is the error I'm getting: HttpError: https://www.googleapis.com/admin/directory/v1/users?orderBy=email&domain=example.com&alt=json&maxResults=10 returned "Not Authorized to access this resource/api">
Follow the steps indicated in Delegating domain-wide authority to the service account:
Then, an administrator of the G Suite domain must complete the following steps:
Go to your G Suite domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
Select Show more and then Advanced settings from the list of options.
Select Manage API client access in the Authentication section.
In the Client Name field enter the service account's Client ID. You can find your service account's client ID in the Service accounts page.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example, if your application needs domain-wide access to the Google Drive API and the Google Calendar API, enter: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
Click Authorize.
Make sure your service account is set to Administrator.

Categories

Resources