Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch request for oauth2 token requests returns 400 Bad Request error #605

Closed
SwapnaReddyL opened this issue Dec 14, 2018 · 34 comments
Closed
Assignees
Labels
type: question Request for information or clarification. Not an issue.

Comments

@SwapnaReddyL
Copy link

SwapnaReddyL commented Dec 14, 2018

I'm using google api client 1.7.4 with python 2.7 and unable to make successful batch requests with new_batch_http_request api. I keep getting 400 Bad Request error

After debugging google api client lib, final request body is following :

`--===============6159072106655335965==
Content-Type: application/http
MIME-Version: 1.0
Content-Transfer-Encoding: binary
Content-ID: <943c8367-618b-4817-97d1-fe4f4005af25+0AL0173QlVaLoUk9PVA%40%40%3F%7C%3F%40%40administrator%40testcloudlockprimary1.com>

POST /oauth2/v4/token HTTP/1.1
Content-Type: application/json; charset=utf-8
MIME-Version: 1.0
Host: www.googleapis.com
content-length: 715

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=<assertion_code>
`

Here is what code looks like :
###code to build batch request and nested requests#######
` logger.info('Refreshing credentials for %s users', len(creds_to_refresh))

   oauth_service = build('oauth2', 'v2', http=LoggingHttp())
    batch_request = oauth_service.new_batch_http_request()

    for request_id, creds in six.iteritems(credentials_to_refresh):
        request = build_token_request(creds)
        batch_request.add(request, request_id=request_id)

    batch_request.execute()

   def build_token_request(creds):
        request = HttpRequest(http=LoggingHttp(), postproc=_postproc,
                      uri=creds.token_uri,
                      method='POST',
                      body=creds._generate_request_body(),
                      headers=creds._generate_request_headers())
         return request

###methods generating request body and headers###

       def _generate_request_body(self):
             assertion = self._generate_assertion()
             body = urllib.parse.urlencode({
                 'assertion': assertion,
                  'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
             })
          return body

     def _generate_request_headers(self):
           """Generate the headers that will be used in the refresh request."""
               headers = {
                             'content-type': 'application/json; charset=utf-8',
                         }
              if self.user_agent is not None:
              headers['user-agent'] = self.user_agent
       return headers

`

@tseaver
Copy link
Contributor

tseaver commented Dec 14, 2018

@SwapnaReddyL Can you please show the full traceback and error message?

@SwapnaReddyL
Copy link
Author

@tseaver It's http error "<HttpError 400 when requesting https://www.googleapis.com/oauth2/v4/token returned "Bad Request">"

Here is what i found in response content :

--batch_gHThtkbBoB8_AAJxz-pPuhE
Content-Type: application/http
Content-ID: <response-6b6d70c6-b4d2-46ef-90d2-9b3a1ab0bfb1+0AB7uSPqRpNOnUk9PVA%40%40%3F%7C%3F%40%40administrator%40testcloudlockprimary1.com>

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=UTF-8
Date: Fri, 14 Dec 2018 21:37:50 GMT
Expires: Fri, 14 Dec 2018 21:37:50 GMT
Cache-Control: private, max-age=0
Content-Length: 103

{
"error": "internal_failure",
"error_description": "The request did not match the specified API."
}

--batch_gHThtkbBoB8_AAJxz-pPuhE--

I couldn't retrieve stack trace information on http error, but attaching screenshot of captured error.

httperror

@busunkim96
Copy link
Contributor

@SwapnaReddyL Do you have a specific reason for interacting with the OAuth2 API directly? In general, we recommend using one of the client libraries to interact with the OAuth2 endpoint. google-auth is the currently maintained library for Python.

@JustinBeckwith JustinBeckwith added the triage me I really want to be triaged. label Dec 15, 2018
@SwapnaReddyL
Copy link
Author

@busunkim96 its a legacy code in our application, i'm just trying to update code to use new_http_batch_request api with oauth2 service.
If "400 bad request" issue can be resolved with google-auth, can you please provide your input on how would above code change?

@SwapnaReddyL
Copy link
Author

Hoping to get some help on this, as this is blocking us on to proceed with google api client upgrade and affecting dependent teams.

@busunkim96
Copy link
Contributor

busunkim96 commented Dec 17, 2018

@SwapnaReddyL The batching looks correct to me (Batch requests in Python).

Note that if you are putting more than 1000 calls in the batch request you will need to make multiple batch requests.

It looks like it's the individual requests that don't have the correct fields.

http error "<HttpError 400 when requesting https://www.googleapis.com/oauth2/v4/token returned "Bad Request">"

A refresh request needs refresh_token, client_id, client_secret, and grant_type. Here is the documentation on refreshing an access token.

A refresh request should look like this:

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=<your_client_id>&
client_secret=<your_client_secret>&
refresh_token=<refresh_token>&
grant_type=refresh_token

And returns a response

{
  "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in":3920,
  "token_type":"Bearer"
}

@busunkim96 busunkim96 added type: question Request for information or clarification. Not an issue. and removed triage me I really want to be triaged. labels Dec 17, 2018
@busunkim96
Copy link
Contributor

If you do decide to use google-auth, the object will refresh the access token as needed.

https://developers.google.com/identity/protocols/OAuth2WebServer#offline

Access tokens periodically expire. You can refresh an access token without prompting the user for permission (including when the user is not present) if you requested offline access to the scopes associated with the token.

If you use a Google API Client Library, the client object refreshes the access token as needed as long as you configure that object for offline access.

This guide walks through how to use google-auth: OAuth2.0 for Web Server Applications

@SwapnaReddyL
Copy link
Author

SwapnaReddyL commented Dec 18, 2018

I still see same issue with request matching to documentation

`
--===============6986313775479449592==
Content-Type: application/http
MIME-Version: 1.0
Content-Transfer-Encoding: binary
Content-ID: <b930b9ed-a31e-4a93-a637-4f7ff876a3ce+0AB3OY9kg45UOUk9PVA%40%40%3F%7C%3F%40%40administrator%40testcloudlockprimary1.com>

POST /oauth2/v4/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
MIME-Version: 1.0
Host: www.googleapis.com
content-length: 1165

client_secret=<client_secret_key>&client_id=<client_id>&refresh_token=&grant_type=refresh_token
--===============6986313775479449592==--

`

And same request works fine when we directly invoke BatchHttpRequest.init instantiation which uses "https://www.googleapis.com/batch" batch_uri . It is failing when we create batch request using new_batch_http_request and in this case batch_uri is "https://www.googleapis.com/batch/oauth2/v2"

@SwapnaReddyL
Copy link
Author

Is there input on this batch request failure for "https://www.googleapis.com/batch/oauth2/v2" batch uri?
Also in terms of response, it only shows 400 Bad Request. Is there a way to get more data on error, like what is wrong and what is expected? At this point its been really hard to figure out why the request is Bad.

@busunkim96
Copy link
Contributor

Hey @SwapnaReddyL. Sorry about the confusion, I'm still learning about this myself. To summarize, it looks like things are working as intended. I would recommend you read all of OpenID Connect, which explains the OAuth2.0 flow from beginning to end.

The Google OAuth2 API only deals with the authorization_endpoint, which is one of several endpoints involved in OAuth. As a result, the client library functions for this API only let you interact with the authorization endpoint.

To get a refresh token, you need to make requests to the token_endpoint. Since the token_endpoint is not the same as the authorization_endpoint, batch requests made through the new_batch_http_request fail.

@SwapnaReddyL
Copy link
Author

SwapnaReddyL commented Dec 19, 2018

@busunkim96 thanks for information. But nested requests in batch does use token_endpoint "POST /oauth2/v4/token HTTP/1.1" . Is the oauth2 service build('oauth2', 'v2', http=LoggingHttp()) right batch service for nested token requests?

I also tried with "v1" version and by passing discoveryservice url manually "oauth_service = build('oauth2', 'v1', http=LoggingHttp(), discoveryServiceUrl='https://{api}.googleapis.com/$discovery/rest?'
'version={apiVersion}')"

I see "HTTP/1.1 404 Not Found" issue now.

@busunkim96
Copy link
Contributor

I am doing some more investigating internally to see if this is the intended behavior. Unfortunately it may be a while because of the approaching holidays in the US.

For now, you should be able to make a batch request to the token endpoint using raw HTTP requests.

batch = BatchHttpRequest(batch_uri="https://oauth2.googleapis.com/batch", callback=callback)

for c in credentials:
    body = generate_request_body(c)
    batch.add(HttpRequest(
        httplib2.Http(),
        post_proc,
        "/token",
        method="POST",
        body=body,
        )
    )

batch.execute()

@SwapnaReddyL
Copy link
Author

SwapnaReddyL commented Dec 20, 2018

We were doing batch request by directly invoking BatchHttpRequest.init initialization method, which actually uses "https://www.googleapis.com/batch". The reason we are trying to switching to new_http_batch_requests is due to WARNING seen after api client library upgrade.

"You have constructed a BatchHttpRequest using the legacy batch "
"endpoint %s. This endpoint will be turned down on March 25, 2019. "
"Please provide the API-specific endpoint or use "
"service.new_batch_http_request(). For more details see "
"https://developers.googleblog.com/2018/03/discontinuing-support-for-json-rpc-and.html"
"and https://developers.google.com/api-client-library/python/guide/batch.",

@busunkim96
Copy link
Contributor

Yes, the global batch endpoint is being turned down. Please try https://oauth2.googleapis.com/batch which seems to be the batch endpoint for the token endpoint https://oauth2.googleapis.com/token.

@SwapnaReddyL
Copy link
Author

No luck yet. I still see 404 Not found with "Invalid Request" error.
I'm using similar request for "drive" service and that works fine. Issue is just with oauth url.

@busunkim96
Copy link
Contributor

Could you provide a code snippet and/or the requests and responses you're getting?

@busunkim96
Copy link
Contributor

busunkim96 commented Dec 20, 2018

Please try the following combination of URIs

BatchHttpRequest URI: https://oauth2.googleapis.com/batch
HttpRequest URI: https://oauth2.googleapis.com/token (instead of the value in credentials.token_uri)

batch_request = BatchHttpRequest(batch_uri='https://oauth2.googleapis.com/batch')

for request_id, creds in six.iteritems(credentials_to_refresh):
    request = build_token_request(creds)
    batch_request.add(request, request_id=request_id)

batch_request.execute()

def build_token_request(creds):
    request = HttpRequest(http=LoggingHttp(), postproc=_postproc,
                  uri='https://oauth2.googleapis.com/token',
                  method='POST',
                  body=creds._generate_request_body(),
                  headers=creds._generate_request_headers())
     return request

I suspect other combinations will work. It looks like what matters is that the outer BatchHttpRequest's URI and the inner request URI's match.

BatchHttpRequest URI: https://www.googleapis.com/oauth2/v4/batch
HttpRequest URI: https://www.googleapis.com/oauth2/v4/token

OR

BatchHttpRequest URI: https://www.googleapis.com/oauth2/v3/batch
HttpRequest URI: https://www.googleapis.com/oauth2/v3/token

@SwapnaReddyL
Copy link
Author

SwapnaReddyL commented Dec 20, 2018

I had shared request body in the same thread.

        batch_request = BatchHttpRequest(batch_uri="https://oauth2.googleapis.com/batch", 
       callback=self._callback())
       
        # oauth_service = build('oauth2', 'v1', http=LoggingHttp(), 
               discoveryServiceUrl='https://{api}.googleapis.com/$discovery/rest?'
        #             'version={apiVersion}')
        # batch_request = oauth_service.new_batch_http_request()
            
                for request_id, credentials in six.iteritems(credentials_to_refresh):
                     user, auth_user = decode_request_id(request_id)
                     request = build_http_token_request(credentials)
                     batch_request.add(request, request_id=request_id)
        batch_request.execute()
     
      def build_http_token_request(oauth2credentials):
            request = HttpRequest(http=LoggingHttp(), postproc=_postproc,
                          uri='https://www.googleapis.com/oauth2/v4/token',
                          method='POST',
                          body=oauth2credentials._generate_refresh_request_body(),
                          headers=oauth2credentials._generate_refresh_request_headers())
        return request
       
           def _generate_refresh_request_body(self):
           #assertion or JWT is generated using client id and client secret signer
                 assertion = self._generate_assertion()
      
             **Following works for legacy batch uri, we didn't store refresh_token but used JWT token,  
            same credentials doesn't work with new uri**
            # body = urllib.parse.urlencode({
            #     'assertion': assertion,
            #     'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer'
            # })

         **I also tried with following request params -**
          body = urllib.parse.urlencode({
               'refresh_token': assertion,
               'client_id': self.client_id,
               'client_secret': self.client_secret,
               'grant_type': 'refresh_token'
           })

        return body

      def _generate_assertion(self):
             """Generate the assertion that will be used in the request."""
            now = int(time.time())
            payload = {
               'aud': self.token_uri,
               'scope': self._scopes,
               'iat': now,
               'exp': now + self.MAX_TOKEN_LIFETIME_SECS,
               'iss': self._service_account_email,
            }
            payload.update(self._kwargs)
            return crypt.make_signed_jwt(self._signer, payload,
                                     key_id=self._private_key_id)
`

Here is the content of response:

--batch_ZJWyNepBKCPY3oklXhjbSTYjmUobA0Bi
Content-Type: application/http
Content-ID: <response-ed3656c2-f2cb-400e-b7d0-f8d03da2b8e3 + 0ANf8v7v4c7HEUk9PVA%40%40%3F%7C%3F%40%40administrator%40testcloudlockprimary1.com>

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Vary: Origin
Vary: X-Origin
Vary: Referer

{
  "error": "invalid_request"
}
--batch_ZJWyNepBKCPY3oklXhjbSTYjmUobA0Bi--

@SwapnaReddyL
Copy link
Author

I received your response right after my comment, i will try out those combinations and let you know. But can you also take look at the body params in my comment?

@SwapnaReddyL
Copy link
Author

I tried "https://oauth2.googleapis.com/batch and https://oauth2.googleapis.com/token" combinations

I see following with different body that i had explained above:
`
def _generate_refresh_request_body(self):
assertion = self._generate_assertion()

     body = urllib.parse.urlencode({
         'assertion': assertion,
        'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer'
     })

`

Response is
--batch_3GIh3qXda-awwMnSDzaM6cQWpFMPFK95
Content-Type: application/http
Content-ID: <response-3c54099e-6cc1-4772-95dd-77535141753c + 0ACqRq2okl1RkUk9PVA%40%40%3F%7C%3F%40%40administrator%40testcloudlockprimary1.com>

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Vary: Origin
Vary: X-Origin
Vary: Referer

{
"error": "invalid_grant",
"error_description": "Invalid JWT: Failed audience check. The right audience is https://oauth2.googleapis.com/token"
}
--batch_3GIh3qXda-awwMnSDzaM6cQWpFMPFK95--

`

       def _generate_refresh_request_body(self):
            assertion = self._generate_assertion()

       body = urllib.parse.urlencode({
            'refresh_token': assertion,
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'grant_type': 'refresh_token'
          })

    return body

`

Response is

--batch_X8Tdwmm-Kh72Cc16wMPR-4W5kX-v1QZg
Content-Type: application/http
Content-ID: <response-9470c95f-10f0-4c7a-8cce-c74dfdbb0894 + 0ACqRq2okl1RkUk9PVA%40%40%3F%7C%3F%40%40administrator%40testcloudlockprimary1.com>

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Vary: Origin
Vary: X-Origin
Vary: Referer

{
"error": "invalid_client",
"error_description": "Unauthorized"
}
--batch_X8Tdwmm-Kh72Cc16wMPR-4W5kX-v1QZg--

@busunkim96
Copy link
Contributor

busunkim96 commented Dec 20, 2018

The body should like like the second one you have.
https://developers.google.com/identity/protocols/OAuth2WebServer#offline

          body = urllib.parse.urlencode({
               'refresh_token': assertion,
               'client_id': self.client_id,
               'client_secret': self.client_secret,
               'grant_type': 'refresh_token'
           })

Everything looks fine except for the refresh_token field. The refresh_token is a special token you should have received the first time the user authenticated.

Is there a self.refresh_token?

Your application should store both tokens in a secure, long-lived location that is accessible between different invocations of your application. The refresh token enables your application to obtain a new access token if the one that you have expires. As such, if your application loses the refresh token, the user will need to repeat the OAuth 2.0 consent flow so that your application can obtain a new refresh token.

https://developers.google.com/identity/protocols/OAuth2WebServer#exchange-authorization-code

@SwapnaReddyL
Copy link
Author

@busunkim96 thanks for your continuous support!
I will also try to work with team about "refresh_token" retrieval, it might take little time with holidays around.

@bobbycloudlock
Copy link

Hi @busunkim96 , thanks for the helps on this issue.

Some clarification w.r.t the context. The way we are using is Service Account, which uses JSON Web Token (JWT) Profile for OAuth 2.0, In contrast to other OAuth 2.0 profiles, no users are involved and the application "acts" as the service account. This should also be the reason why you saw it use grant_type=jwt-bearer instead of grant_type=refresh_token when it attempts to refresh the access_token.

More specifically, our service accounts use domain-wide delegation_ authority to access user data on behalf of users in the domain.

So the problem sounds like the NEW Token URL you provided somehow doesn't like the token request coming from Service Account refresh access_token request(which is asking for JWT-bear grant type) ?

BatchHttpRequest URI: https://oauth2.googleapis.com/batch
HttpRequest URI: https://oauth2.googleapis.com/token

Yes, our legacy code is heavily relying on oauth2client(2.0.1), which seems to need upgrade to google-auth at some point(It would be a much larger changes for us).

But on the other hand, from what I can see that the latest google-auth library(replacement of oauth2client) does support service account well - So I suspect JWT grant_type should still be working, but we need to find how to migrate service account related code when doing the upgrade ?

https://github.com/googleapis/google-auth-library-python/blob/edfe24602051969e32917e82bcedd2bace43e260/google/oauth2/service_account.py

With this additional information added, do you have any suggestion ?

Any help would be highly appreciated.

thank you

-Bobby

@SwapnaReddyL
Copy link
Author

SwapnaReddyL commented Jan 11, 2019

@busunkim96 @tseaver I'm sharing a script which helps to reproduce the issue that we see in our application to refresh access token using oauth2client service account and googleapiclient.http BatchHttpRequest .
Script prints exact error message.
Please use this script to debug. Considering march deadline to support legacy batch uri, we are hoping if you could provide your support to understand if there is equivalent token api to accept service account assertion token(JWT) instead of refresh_token to retrieve access token.

Also it might helpful to know, if there is a way to find source code for these new oauth2 token end points to debug.
Hoping to get some help!!

Here is the script that simulates our workflow to reproduce the issue and error

#!/usr/bin/python

import httplib2
import json
import pkg_resources

from googleapiclient.http import HttpRequest, BatchHttpRequest
from oauth2client import client, crypt, service_account
from ConfigParser import SafeConfigParser

scope = 'https://www.googleapis.com/auth/drive'
# GOOGLE_OAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v3/token'
GOOGLE_OAUTH_TOKEN_URI = 'https://oauth2.googleapis.com/token'

def main():
    # while True:
        batch_request = BatchHttpRequest(batch_uri="https://oauth2.googleapis.com/batch",
                                         callback=None)

        credentials1 = getCredentials('new_api@testcloudlockprimary1.com')
        request1 = build_http_token_request(credentials1)

        credentials2 = getCredentials('aa@testcloudlockprimary1.com')
        request2 = build_http_token_request(credentials2)

        batch_request.add(request1,
                          request_id='new_api@testcloudlockprimary1.com@@?|?@@new_api@testcloudlockprimary1.com')
        batch_request.add(request2, request_id='aa@testcloudlockprimary1.com@@?|?@@aa@testcloudlockprimary1.com')

        batch_request.execute()

        print batch_request._responses['new_api@testcloudlockprimary1.com@@?|?@@new_api@testcloudlockprimary1.com']

        print batch_request._responses['aa@testcloudlockprimary1.com@@?|?@@aa@testcloudlockprimary1.com']

        return


def _postproc(resp, content):
    return json.loads(content)


def build_http_token_request(credentials):
    """
    Build an actual http request to renew access token
    :param oauth2credentials: an instance of oauth2client.client.OAuth2Credentials or its subclass
    :return: HttpRequest
    """
    request = HttpRequest(http=httplib2.Http(), postproc=_postproc,
                          uri='https://oauth2.googleapis.com/token',
                          method='POST',
                          body=credentials._generate_refresh_request_body(),
                          headers=credentials._generate_refresh_request_headers())
    return request


def getCredentials(user):
    dev_keys = load_config_filename('client_secret.ini')
    _client_id = dev_keys['client_id']
    _client_secret = dev_keys['client_secret']
    credentials = service_account.ServiceAccountCredentials(
        _client_id, crypt.OpenSSLSigner.from_string(_client_secret),
        scopes=scope, token_uri=GOOGLE_OAUTH_TOKEN_URI
    ).create_delegated(user)
    credentials._private_key_pkcs8_pem = _client_secret

    return credentials


def load_config_filename(filename, section='DEFAULT'):
    conf = SafeConfigParser()
    conf.read(filename)
    result = dict(conf.items(section))
    return result

if __name__ == '__main__':
    main()


@busunkim96
Copy link
Contributor

@bobbycloudlock Ah that makes sense. This is the guide on the OAuth 2.0 guide with service accounts, in case you haven't seen it yet. OAuth 2.0 for Service Accounts

The JWT grant_type works fine with the token endpoint https://oauth2.googleapis.com/token. You can test this yourself with the sample curl command provided in the OAuth 2.0 for Service Accounts guide.

curl -d 'grant_typeurn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

Response:

{
  "error": "invalid_grant",
  "error_description": "Not a valid email or user ID."
}

Note that the error is invalid_grant rather than invalid_grant_type.

@SwapnaReddyL’s script looks like it’s trying to use the OAuth2Credential’s method to refresh the token, which is separate from the service account flow. You should reference the function _generate_assertion in oauth2client/serviceaccount.py for generating the correct assertion. It will end up look more like to the code you provided earlier in your original post.

@SwapnaReddyL
Copy link
Author

SwapnaReddyL commented Jan 12, 2019

@busunkim96 during run time oauth2client/serviceaccount.py:: _generate_assertion method is invoked to generate assertion. With that we see invalid_grant error

Following is the error message:

/Users/swareddy/Documents/GitHub/platform-core2/npvenv/bin/python /Users/swareddy/Documents/GitHub/quickstart-python/drive/driveapp/oauthReq.py
({'status': '400', 'vary': 'Referer', 'content-type': 'application/json; charset=utf-8'}, '{\n "error": "invalid_grant",\n "error_description": "Invalid JWT: Failed audience check. The right audience is https://oauth2.googleapis.com/token"\n}')
({'status': '400', 'vary': 'Referer', 'content-type': 'application/json; charset=utf-8'}, '{\n "error": "invalid_grant",\n "error_description": "Invalid JWT: Failed audience check. The right audience is https://oauth2.googleapis.com/token"\n}')

But we do use "https://oauth2.googleapis.com/token" in our request, as per your suggestion. Script references to "https://oauth2.googleapis.com/token"

@SwapnaReddyL
Copy link
Author

@busunkim96 Please provide your input on error message shared in previous message. Assertion code generated by same script works with legacy batch uri and "https://www.googleapis.com/oauth2/v3/token" api end points.

@busunkim96
Copy link
Contributor

Please confirm that the aud claim in the JWT claimset is set to https://oauth2.googleapis.com rather than https://www.googleapis.com/oauth2/v3/token.

@SwapnaReddyL
Copy link
Author

@busunkim96 by changing token_uri=GOOGLE_OAUTH_TOKEN_URI to aud=GOOGLE_OAUTH_TOKEN_URI in getCredentials method within script, helps to generate access token .
And yes GOOGLE_OAUTH_TOKEN_URI uses https://oauth2.googleapis.com

I'm going to integrate changes in our product and hoping things would work.
Thanks a lot for your input!
Will touch base on outcome of integration!

@SwapnaReddyL
Copy link
Author

@busunkim96 based on our last solution in terms of updating audiences list, token batch request was working with
batch_request = BatchHttpRequest(batch_uri="https://oauth2.googleapis.com/batch",
callback=None) . But today i noticed that "https://oauth2.googleapis.com/batch" url doesn't work anymore . We were above to push our updated changes and its very disappointing to see this issue at the last moment. @busunkim96 please provide your input/help asap.

Note we are using following version of libs:
google-api-python-client==1.7.6
oauth2client==4.1.3

Following is the stack trace:

/Users/swareddy/Documents/GitHub/platform-core2/npvenv/bin/python /Users/swareddy/Documents/GitHub/quickstart-python/drive/driveapp/oauthReq.py
Traceback (most recent call last):
File "/Users/swareddy/Documents/GitHub/quickstart-python/drive/driveapp/oauthReq.py", line 104, in
main()
File "/Users/swareddy/Documents/GitHub/quickstart-python/drive/driveapp/oauthReq.py", line 52, in main
batch_request.execute()
File "/Users/swareddy/Documents/GitHub/platform-core2/npvenv/lib/python2.7/site-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
return wrapped(*args, **kwargs)
File "/Users/swareddy/Documents/GitHub/platform-core2/npvenv/lib/python2.7/site-packages/googleapiclient/http.py", line 1450, in execute
self._execute(http, self._order, self._requests)
File "/Users/swareddy/Documents/GitHub/platform-core2/npvenv/lib/python2.7/site-packages/googleapiclient/http.py", line 1385, in _execute
raise HttpError(resp, content, uri=self._batch_uri)
googleapiclient.errors.HttpError: <HttpError 404 when requesting https://oauth2.googleapis.com/batch returned "Not Found">

Process finished with exit code 1

@busunkim96
Copy link
Contributor

There was an internal bug, but it looks like it has been resolved as of today. Please let us know if you have any other problems.

@SwapnaReddyL
Copy link
Author

Thanks for confirming. Works now.

@himalr
Copy link

himalr commented Mar 26, 2020

Edit: Moved to #853

@busunkim96 Done. Thanks.

@busunkim96
Copy link
Contributor

@himalr Please open a new issue with your question. Repository maintainers are less likely to see posts to already-closed issues.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: question Request for information or clarification. Not an issue.
Projects
None yet
Development

No branches or pull requests

6 participants