Permission denied error when using Google Oauth2 access token

4,636 views
Skip to first unread message

Sudharsan R

unread,
Jun 2, 2016, 6:58:34 PM6/2/16
to Firebase Google Group
I am facing error : Permission denied while authenticating with Firebase using Google Oauth2 access token. The steps are listed below.

Code to generate access token

from __future__ import print_function
import json
import apiclient
from apiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials


class Firebase(object):
   
def __init__(self,keyFile):
       
self._scopes = ['https://www.googleapis.com/auth/firebase.database']

       
self._credentials = ServiceAccountCredentials.from_json_keyfile_name(keyFile,self._scopes)

       
print(self._credentials.get_access_token())


g
=Firebase('config/SHORTURL-71318685345b.json')


Running the script at 3.54 PM MT
$ py firebase.py
AccessTokenInfo(access_token='ya29.CjD1AtWK0psCP-uj-n_k2cxhM9MTut1jfDG_-FLWNTkvkeh_KmPUoPu8DvtwhZN7_YM', expires_in=3600)




Accessing database at 3.55 PM MT
$ curl https://shorturl-1267.firebaseio.com/.json?access_token=ya29.CjD1AtWK0psCP-uj-n_k2cxhM9MTut1jfDG_-FLWNTkvkeh_KmPUoPu8DvtwhZN7_YM
 
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 
Dload  Upload   Total   Spent    Left  Speed
100    37  100    37    0     0     57      0 --:--:-- --:--:-- --:--:--    57{
 
"error" : "Permission denied."
}




I am able to use a same approach of generating the access_token for urlshortener scope and list. I modified the scope to urlshortner
class ShortUrl(object):
   
def __init__(self,keyFile):
       
self._scopes = ['https://www.googleapis.com/auth/urlshortener']
       
self._credentials = ServiceAccountCredentials.from_json_keyfile_name(keyFile,self._scopes)
       
print(self._credentials.get_access_token())
g
=ShortUrl('config/SHORTURL-71318685345b.json')



Running the script at 3.57 PM MT
$ py shorturl.py
AccessTokenInfo(access_token='ya29.CjP1Aqd4nU3cGtl8k_m7FSU8kdRxgOmAR-lkWi0862fVhTBysv3wWlvbdo_tWFGXzs1GNGw', expires_in=3600)


Hitting the url for urlshortener 3.58 PM MT (Works eventhough jwt.io says token malformed)
$ curl https://www.googleapis.com/urlshortener/v1/url/history?access_token=ya29.CjP1Aqd4nU3cGtl8k_m7FSU8kdRxgOmAR-lkWi0862fVhTBysv3wWlvbdo_tWFGXzs1GNGw
 
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 
Dload  Upload   Total   Spent    Left  Speed
100  3828  100  3828    0     0   9428      0 --:--:-- --:--:-- --:--:--  9428{
 
"kind": "urlshortener#urlHistory",
 
"totalItems": 21,
 
"itemsPerPage": 30,
 
"items": [



I am following Firebase documentation as per the below link


Due to some reason, either the generated jwt signature is incorrect or firebase is unable to parse it. As per the below documentation in github,
using ServiceAccountCredentials seems to be a fair approach
I would have gone ahead with the build() and execute() if firebase was part of discovery apis of google. But it is not. Hence, I print it out and tested with curl.

Kindly advice.

Kato Richardson

unread,
Jun 2, 2016, 7:12:33 PM6/2/16
to Firebase Google Group
Sudharsan,

Great to hear from you! Michael Bleigh gave a pretty authoritative answer on rest tokens here. It looks like you've already found and commented there.

I can't help but notice that your code isn't using googleapis or calling authorize. Could you try out his sample and see if you have better results? If so, we may be able to work backward to see what's failing.

☼, Kato

--
You received this message because you are subscribed to the Google Groups "Firebase Google Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to firebase-tal...@googlegroups.com.
To post to this group, send email to fireba...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/firebase-talk/1dad4c46-919d-49a9-b5be-863d97fb6c91%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Kato Richardson | Developer Programs Eng | kato...@google.com | 775-235-8398

Sudharsan R

unread,
Jun 2, 2016, 8:08:22 PM6/2/16
to Firebase Google Group
Hi Kato,
Since you asked, I am pasting the authorize code here. It will make no difference apart from adding additional headers - The token remains the same. I have also listed a link down below where we have the same problem with .NET using REST API.

class Firebase(object):
   
def __init__(self,keyFile):
       
self._API_KEY = 'AIzaSyAwWRMFi_l5PStENHDn1i8QF060T_Hdc-k'

       
self._scopes = ['https://www.googleapis.com/auth/firebase.database']
       
self._credentials = ServiceAccountCredentials.from_json_keyfile_name(keyFile,self._scopes)

        h
= self._credentials.authorize(httplib2.Http())
       
print(self._credentials.get_access_token())
       
print(h.request.credentials.get_access_token())
g=Firebase('config/SHORTURL-71318685345a.json')

Running the script at 5.18 PM MT
$ py firebase.py
AccessTokenInfo(access_token='ya29.CjD1AvvkPqskoxKsoIZVq6mI74Q1EPhJgL6LWsAyNIhm8n8YNJ59I0iqqJwtwELO0SM', expires_in=3600)
AccessTokenInfo(access_token='ya29.CjD1AvvkPqskoxKsoIZVq6mI74Q1EPhJgL6LWsAyNIhm8n8YNJ59I0iqqJwtwELO0SM', expires_in=3599)


I have already included firebase.database as part of scope. The stackoverflow example follows nodejs, but the problem here is access_token (generated by google oauth2 apiclient) is not jwt compliant

I found one other person who faced the same problem. Posing the link here. It is in .NET.

Firebase documentation is listed below. I have followed the exact same steps. But the example database used here is public and hence it is returning the result. Can you pls check the below example by making the db private, so that we can see if something comes up in that direction.
GoogleCredential googleCred = GoogleCredential.fromStream(new FileInputStream("service_account.json"));
GoogleCredential scoped = googleCred.createScoped(
   
Arrays.asList("https://www.googleapis.com/auth/firebase.database"));
scoped
.refreshToken();
String token = scoped.getAccessToken();

curl 'https://samplechat.firebaseio-demo.com/users/jack/name.json?access_token=<TOKEN>'

Chris Raynor

unread,
Jun 2, 2016, 8:12:59 PM6/2/16
to Firebase Google Group
I think your problem is that you're not including the 'https://www.googleapis.com/auth/userinfo.email' OAuth scope. Have you tried adding that?

Unfortunately for the time being it's required

Chris

Sudharsan R

unread,
Jun 2, 2016, 9:10:11 PM6/2/16
to Firebase Google Group
Chris, you are amazing.. It worked!!! 
I added the scope as below -


Thanks a ton!

Chris Raynor

unread,
Jun 2, 2016, 9:45:13 PM6/2/16
to Firebase Google Group
Glad you got it working, I'll make sure the documentation is updated.

One final FYI about using OAuth2 access tokens for authentication that also doesn't seem too clear from the documentation - these give you blanket admin read-only or read/write access to the database (depending on the IAM role of the service account on the project and whether you request the https://www.googleapis.com/auth/firebase.database scope or the https://www.googleapis.com/auth/firebase.database.readonly scope) and completely bypass security rules.

Sudharsan R

unread,
Jun 2, 2016, 11:02:06 PM6/2/16
to Firebase Google Group
Thanks Chris for the useful info. One other thing - auth keyword is used for firebase secret and access_token is used for oauth2 token in the URL. The documentation says to use access_token for both. May need an update there too. Thanks

Joris Mak

unread,
Nov 29, 2016, 7:46:19 PM11/29/16
to Firebase Google Group
Yes finally got it working here too using only REST stuff!

The documentation for Firebase seems to be a mess on this (still, looking at the dates months after the start of this topic)

Some docs say to use 'iss: <service email>' in the JWT packet and to also use 'sub: <service email>'. But you only have to use 'iss', including 'sub:' gives an error about "Unauthorized client or scope in request."


And none of the Firebase docs mention the scopes required. I was testing a lot of time with the scope of the 'Firebase Rules API' as it seemed the best match.

Now (indeed as shown above) it's clear you have to use at least two scopes:

This makes the minimal JWT json packet (before the whole JWT encoding + signing and all):
{
 
"iss":"blab...@blablabla.iam.gserviceaccount.com",
 
"scope":"https://www.googleapis.com/auth/firebase.database https://www.googleapis.com/auth/userinfo.email",
 
"aud":"https://www.googleapis.com/oauth2/v4/token",
 
"exp":<unix timestamp of max request time, max 3600 seconds in the future>,
 
"iat":<unix timestamp of 'now'>
}

Then, the REST Auth docs (which you have to find by Googling or hitting a lucky link, they're not in the reference or something) say to use an url parameter 'auth' in your request. So you get ?auth=<creds>. The docs mention that <creds> can be your firebase-database general 'secret', or a token. But if you try to pass the token you got from the JWT Oauth phase, you'll get an error about unable to parse the token. You need to use ?access_token=<token> if you want to use the Service Account token, and you'll have to use ?auth=<secret> if you want to use the firebase-secret.
(Or the extra HTTP header 'Authorization: Bearer <token>' which also seems to work).

Figuring this all out (while also getting the JWT encoding and signing to be acceptable without any SDK, nothing to do with Firebase just my 'newb-ness' to JWT and OAuth) has taken way longer than I was hoping for :S.

I'm a bit baffled by the state of the REST documentation, as in my mind it's still the 'basis' on which the rest is all built. Making SDKs for iOS, Android and Javscript and leaving the rest to 'fend for themselves' through REST is perfectly fine, no problem there. But at least make sure the REST documentation is OK so people can build their own libraries on top of it.
Reply all
Reply to author
Forward
0 new messages