Firebase Admin SDK - Python - python

Recently the FB Admin SDK was introduced for Python as well, and here is a repo with some samples.
It's nice I can authenticate using credentials, and finally I have a firebase_admin authenticated which can create Custom Tokens too. But how can it help to do requests for the REST API e.g? Can I retrieve my authentication token and set it as Authorization header maybe to do API requests?

You should be able to get an OAuth token by calling the get_access_token() method on your credential, and then pass it to the REST API as described here.
However, in the v1.0.0 of the Python Admin SDK, the returned credential does not contain the Firebase scopes. Therefore the OAuth token obtained from the credential will not readily work with the REST API. This is a bug, and it will be addressed in a future release. In the meantime you can use the following trick:
from firebase_admin import credentials
scopes = [
'https://www.googleapis.com/auth/firebase.database',
'https://www.googleapis.com/auth/userinfo.email'
]
cred = credentials.Certificate('path/to/serviceKey.json')
token = cred.get_credential().create_scoped(scopes).get_access_token().access_token
# Pass token to REST API
In a future release, once the bug has been fixed, you will be to do the following:
from firebase_admin import credentials
cred = credentials.Certificate('path/to/serviceKey.json')
token = cred.get_access_token().access_token
# Pass token to REST API

Related

How do you refresh an authentication token with Authlib and GSpread?

I'm using gspread in a python app to access some backend Google Sheets that act as a database for the application. The user is required to log into the app using an in app browser and an authlib OAuth2 session is created using the token returned in the url via this method. The initial log in and access works fine, but when the token times out after an hour I access the sheets anymore and the app breaks.
I can't work out how to refresh the token using authlib, the reason we picked the library is because it integrated with gspread and the it was supposed to autorefresh auth tokens for you. The code that I use for login is below but after an hour the gspread function open_by_key() fails because of the authentication problem.
I have tried recreating the gspread client, but that just uses the same token. I feel like there should be a way to refresh the token to extend its life for another hour but I can't find how to do that with authlib.
creds = OAuth2Session(clientId, clientSecret, scope=scope, redirect_uri=redirectUrl)
authUrl, state = creds.create_authorization_url('https://accounts.google.com/o/oauth2/v2/auth', response_type='token')
Load the authURL in the browser and get user to log in. Browser returns the authentication response as urlString
creds.fetch_access_token(authorization_response=urlString)
gc = gspread.Client(None, creds)
ss = gc.open_by_key(sheetKey)
todaysSheetName = datetime.datetime.now().strftime('%d-%m-%Y')
wks = ss.worksheet(todaysSheetName)
authUrl, state = creds.create_authorization_url('https://accounts.google.com/o/oauth2/v2/auth', response_type='token')
According to this code you are using, response_type=token is an implicit grant type flow. I guess there won't be a refresh_token in token with implicit flow. Here are my suggestions:
try change it to authorization code flow
use a database to save tokens
if the token is expired, use your previously saved token's refresh_token to exchange a new token.
The refresh_token method is simple:
refresh_token(url=None, refresh_token=None, body='', auth=None, headers=None, **kwargs)
Using your code, it should be:
refresh_token = your_previous_token.refresh_token
new_token = creds.refresh_token('https://accounts.google.com/...', refresh_token=refresh_token)
The problem is that there is no documentation on this part. But according to the API, it would be used like this. If it is not working, you can report it to Authlib issue tracker.

Use Google API with a token [Django & AllAuth]

I am using AllAuth on my Django app to manage user authentication. With that my users can connect their Google accounts and i get a google API token (with appropriate scopes).
I would like to use that token to access google APIs (Calendar v3 in my case) with that token, as my user already used OAuth2 to sign-in on my website, and gave me access to the calendar API.
Google only gives the full process on their website (from auth to api), is there a way to build my idea, or is it simply impossible?
i have tries drive = build('calendar', 'v3', credentials=credentials) as said here but "credentials" needs to be part of an oauth2client and not just a simple string token.
Thank you for your precious time.
Simon
I know its an older question but I finally found something that worked for me. After a successful authentication with allauth, I did this to get the client token and then build the service.
from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from allauth.socialaccount.models import SocialToken, SocialApp
...
# request is the HttpRequest object
token = SocialToken.objects.get(account__user=request.user, account__provider='google')
credentials = Credentials(
token=token.token,
refresh_token=token.token_secret,
token_uri='https://oauth2.googleapis.com/token',
client_id='client-id', # replace with yours
client_secret='client-secret') # replace with yours
service = build('calendar', 'v3', credentials=credentials)

how to obtain GCR access token with python / listing docker images

The access token im getting with gcloud auth print-access-token is obviously a different access token than the one i can get with some basic python code:
export GOOGLE_APPLICATION_CREDENTIALS=/the-credentials.json
from oauth2client.client import GoogleCredentials
credentials = GoogleCredentials.get_application_default()
credentials.get_access_token()
What i am trying to do is get a token that would work with:
curl -u _token:<mytoken> https://eu.gcr.io/v2/my-project/my-docker-image/tags/list
I'd prefer not to install gcloud utility as a dependency for my app, hence my tries to obtain the access token progrmatically via oath google credentials
I know this is a very old question, but I just got faced with the exact same problem of requiring an ACCESS_TOKEN in Python and not being able to generate it, and managed to make it work.
What you need to do is to use the variable credentials.token, except it won't exist once you first create the credentials object, returning None. In order to generate a token, the credentials must be used by a google.cloud library, which in my case was done by using the googleapiclient.discovery.build method:
sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta4', credentials=credentials)
response = sqladmin.instances().get(project=PROJECT_ID, instance=INSTANCE_ID).execute()
print(json.dumps(response))
After which the ACCESS_TOKEN could be properly generated using
access_token = credentials.token
I've also tested it using google.cloud storage as a way to test credentials, and it also worked, by just trying to access a bucket in GCS through the appropriate Python library:
from google.oauth2 import service_account
from google.cloud import storage
PROJECT_ID = your_project_id_here
SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
try:
list(storage.Client(project=PROJECT_ID, credentials=credentials).bucket('random_bucket').list_blobs())
except:
print("Failed because no bucket exists named 'random_bucket' in your project... but that doesn't matter, what matters is that the library tried to use the credentials and in doing so generated an access_token, which is what we're interested in right now")
access_token = credentials.token
print(access_token)
So I think there are a few questions:
gcloud auth print-access-token vs GoogleCredentials.get_application_default()
gcloud doesn't set application default credentials by default anymore when performing a gcloud auth login, so the access_token you're getting from gcloud auth print-access-token is going to be the one corresponding to the used you used to login.
As long as you follow the instructions to create ADC's for a service account, that account has the necessary permissions, and the environment from which you are executing the script has access to the ENV var and the adc.json file, you should be fine.
How to make curl work
The Docker Registry API specifies that a token exchange should happen, swapping your Basic auth (i.e. Authorization: Basic base64(_token:<gcloud_access_token>)) for a short-lived Bearer token. This process can be a bit involved, but is documented here under "How to authenticate" and "Requesting a Token". Replace auth.docker.io/token with eu.gcr.io/v2/token and service=registry.docker.io with service=eu.gcr.io, etc. Use curl -u oauth2accesstoken:<mytoken> here.
See also: How to list images and tags from the gcr.io Docker Registry using the HTTP API?
Avoid the question entirely
We have a python lib that might be relevant to your needs:
https://github.com/google/containerregistry

Firebase admin SDK Python - cannot verify custom tokens

I'm trying to play with the firebase admin sdk for python for making custom tokens and verify those while testing my app. Problem is that while I try to verify the token I always get such an error:
ValueError: Firebase ID token has incorrect "aud" (audience) claim. Expected "my_project_id" but got "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
I followed the guide to create the app and making the tokens:
import firebase_admin
from firebase_admin import auth, credentials
cred = credentials.Certificate('/path/to/file.json')
app = firebase_admin.initialize(cred)
custom_token = auth.create_custom_token('some-uid', app=app)
auth.verify_id_token(custom_token, app=app)
and here I get the error. It seems that _TokenGenarator is initialised with the defaults that are coming back from the error. I thought when passing the app it should automatically change those but it's not happening. Am I missing something?
verify_id_token() only accepts ID tokens. Custom tokens do not fall into that category. See this test case. Raising a ValueError is the expected behavior in this case.
ID tokens can be obtained from a client SDK. You can exchange a custom token for an ID token by calling one of the provided signInWithCustomToken() methods.

Move Google EmailSettings API python code from OAuth1 to OAuth2 service account

To use the new Google Directory API we created an OAuth2 "service account" (see Using OAuth 2.0 for Server to Server Applications). This is basically a PKCS #12 file. All of our Directory API scripts work fine with this service account.
We also use the EmailSettings API (Developer's Guide Email Settings API) to manage some of our Google account settings. These scripts did not move to the new API format, so we continue to use the old OAuth1 authentication method. This has, until recently, worked fine. However, it appears that Google is no longer supporting OAuth1 authentication.
So, we need to move the EmailSettings scripts from OAuth1 to our OAuth2 service account. We are using the gdata Python libraries (GitHub google/gdata-python-client) to make calls to the EmailSettings API. This is how we currently authenticate to make EmailSettings API calls:
import gdata.apps.emailsettings.service
# self is an EmailSettingsService object (gdata.apps.emailsettings.service)
self.domain = "mydomain.com"
self.source = "my application name"
token = get OAuth1 token string from a file
self.SetOAuthInputParameters(
gdata.auth.OAuthSignatureMethod.HMAC_SHA1,
consumer_key = token.oauth_input_params._consumer.key,
consumer_secret = token.oauth_input_params._consumer.secret
)
token.oauth_input_params = self._oauth_input_params
self.SetOAuthToken(token)
Using these Python gdata libraries, how do I authenticate using our OAuth2 service account, i.e., the PKCS #12 file, to use the EmailSettings API?
There's another SO question which shows you how to do this but uses the slightly newer gdata.apps.emailsettings.client methods.
If you must stay with gdata.apps.emailsettings.service then you can "hack" OAuth 2.0 onto the object with something like:
Build your OAuth 2.0 credentials object as you are already doing for your Admin SDK Directory API calls.
Build your GData client object as you are already doing in lines 1-3 of your code.
Grab the access token from your credentials object and apply it as a header to your client object:
client.additional_headers = {
'Authorization': u'Bearer %s' % credentials.access_token}
If you get a 401 response (access token expired), repeat 1 and 3 to get and apply a new access token.

Categories