4
votes

I'm trying to make a Python webapp write to Firebase DB using HTTP API (I'm using the new version of Firebase presented at Google I/O 2016).

My understanding so far is that the specific type of write I'd like to accomplish is made with a POST request to a URL of this type:

https://my-project-id.firebaseio.com/{path-to-resource}.json

What I'm missing is the auth part: if I got it correctly a JWT should be passed in the HTTP Authorization header as Authorization : Bearer {token}.

So I created a service account, downloaded its private key and used it to generate the JWT, added it to the request headers and the request successfully wrote to Firebase DB.

Now the JWT has expired and any similar request to the firebase DB are failing.

Of course I should generate a new token but the question is: I wasn't expecting to handle token generation and refresh myself, most HTTP APIs I'm used to require just a static api key to be passed in the request so my webapps could be kept relatively simple by just adding the stati api key string to the request.

If I have to take care of token generation and expiration the webapp logic needs to become more complex (because I'd have to store the token, check if it is still valid and generate a new one when not), or I could just generate a new token for every request (but does this really make sense?).

I'd like to know if there's a best practice to follow in this respect or if I'm missing something from the documentation regarding this topic.

Thanks, Marco


ADDENDUM

This is the code I'm currently running:

import requests
import json
from oauth2client.service_account import ServiceAccountCredentials

_BASE_URL = 'https://my-app-id.firebaseio.com'
_SCOPES = [
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/firebase.database'
]

def _get_credentials():
    credentials = ServiceAccountCredentials.from_json_keyfile_name('my_service_account_key.json', scopes=_SCOPES)
    return credentials.get_access_token().access_token

def post_object():
    url = _BASE_URL + '/path/to/write/to.json'

    headers = {
        'Authorization': 'Bearer '+ _get_credentials(),
        'Content-Type': 'application/json'
    }

    payload = {
                'title': title,
                'message': alert
              }

    return requests.post(url,
                         data=json.dumps(payload),
                         headers=headers)

Currently for every request a new JWT is generated. It doesn't seem optimal to me. Is it possible to generate a token that doesn't expire?

1
Presumably this is for server-side access? What you'll actually want to do most likely is use a Google access token generated from a service account. Here's an example of how to do it in Ruby.Michael Bleigh
Yes, it's for server-side access. What I've ended up doing has been added in the question text. Though I still feel it's not optimal as I'm generating a new JWT every request. For server-side access I'd hoped a static (non-expiring) token could be used.Marco Romano
As of the 3.x SDK we no longer allow a single long lived bearer token for security reasons.Michael Bleigh
I'm also having trouble with the token expiring after an hour. @MichaelBleigh Is the only way to not encounter the token expiration message by refreshing the token before every API request? Or is there a better way to do this? Thanks!Kenneth Truong
Any news on the topic?Al Wld

1 Answers

0
votes

Thanks for the code example. I got it working better by using the credentials.authorize function which creates an authenticated wrapper for http.

from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
import json

_BASE_URL = 'https://my-app-id.firebaseio.com'
_SCOPES = [
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/firebase.database'
] 

# Get the credentials to make an authorized call to firebase    
credentials = ServiceAccountCredentials.from_json_keyfile_name(
    _KEY_FILE_PATH, scopes=_SCOPES)

# Wrap the http in the credentials.  All subsequent calls are authenticated
http_auth = credentials.authorize(Http())

def post_object(path, objectToSave):
  url = _BASE_URL + path

  resp, content = http_auth.request(
      uri=url,
      method='POST',
      headers={'Content-Type': 'application/json'},
      body=json.dumps(objectToSave),
  )

  return content

objectToPost = {
  'title': "title",
  'message': "alert"
}

print post_object('/path/to/write/to.json', objectToPost)