Search code examples
python-3.xgoogle-apigoogle-oauthgoogle-api-clientgoogle-api-python-client

Google Oath2 library raises CSRF warning when calling flow.InstalledAppFlow.from_client_secrets_file()


I have the following python code:

scopes = ['https://www.googleapis.com/auth/drive',
          'https://www.googleapis.com/auth/spreadsheets',
          'https://www.googleapis.com/auth/gmail.compose']


appflow = flow.InstalledAppFlow.from_client_secrets_file(
            "client_secret.json", scopes=scopes
        )

appflow.run_local_server()

credentials = appflow.credentials

return credentials

Everything seems to work fine, it opens a web browser tab and request for user authorization but, when returning to the script, it raises this error:

test_pytest.py:34: in <module>
    HF_CALC = Calculator(SHEET_URLS)
app\helpers\hf_calculations.py:24: in __init__
    self.gspread_accessor = GspreadAccessor()
app\helpers\utilities.py:547: in __init__
    self.google_sheets = self.authorize_google_sheets()
app\helpers\utilities.py:552: in authorize_google_sheets
    credentials = get_credentials()
app\helpers\utilities.py:84: in get_credentials
    appflow.run_local_server()
appvenv\lib\site-packages\google_auth_oauthlib\flow.py:480: in run_local_server
    self.fetch_token(authorization_response=authorization_response)
appvenv\lib\site-packages\google_auth_oauthlib\flow.py:288: in fetch_token
    return self.oauth2session.fetch_token(self.client_config["token_uri"], **kwargs)
appvenv\lib\site-packages\requests_oauthlib\oauth2_session.py:240: in fetch_token
    authorization_response, state=self._state
appvenv\lib\site-packages\oauthlib\oauth2\rfc6749\clients\web_application.py:203: in parse_request_uri_response
    response = parse_authorization_code_response(uri, state=state)
appvenv\lib\site-packages\oauthlib\oauth2\rfc6749\parameters.py:262: in parse_authorization_code_response
    raise MismatchingStateError()
E   oauthlib.oauth2.rfc6749.errors.MismatchingStateError: (mismatching_state) CSRF Warning! State not equal in request and response.

I haven't found the same error with the same method, so no answer has been useful for my case.

EDIT

This is my client_secret.json:

{
    "installed": {
        "client_id": "my_client_id",
        "project_id": "my_project_id",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_secret": "my_client_secret",
        "redirect_uris": [
            "urn:ietf:wg:oauth:2.0:oob",
            "http://localhost"
        ]
    }
}

Solution

  • Based on the error MismatchingStateError it seem that you aren't passing something correctly in your request.

    The error is being produced by this code in oauth2 rfc6749 parameters file.

    
    def parse_authorization_code_response(uri, state=None):
        """Parse authorization grant response URI into a dict.
        If the resource owner grants the access request, the authorization
        server issues an authorization code and delivers it to the client by
        adding the following parameters to the query component of the
        redirection URI using the ``application/x-www-form-urlencoded`` format:
        **code**
                REQUIRED.  The authorization code generated by the
                authorization server.  The authorization code MUST expire
                shortly after it is issued to mitigate the risk of leaks.  A
                maximum authorization code lifetime of 10 minutes is
                RECOMMENDED.  The client MUST NOT use the authorization code
                more than once.  If an authorization code is used more than
                once, the authorization server MUST deny the request and SHOULD
                revoke (when possible) all tokens previously issued based on
                that authorization code.  The authorization code is bound to
                the client identifier and redirection URI.
        **state**
                REQUIRED if the "state" parameter was present in the client
                authorization request.  The exact value received from the
                client.
        :param uri: The full redirect URL back to the client.
        :param state: The state parameter from the authorization request.
        For example, the authorization server redirects the user-agent by
        sending the following HTTP response:
        .. code-block:: http
            HTTP/1.1 302 Found
            Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
                    &state=xyz
        """
        if not is_secure_transport(uri):
            raise InsecureTransportError()
    
        query = urlparse.urlparse(uri).query
        params = dict(urlparse.parse_qsl(query))
    
        if state and params.get('state', None) != state:
            raise MismatchingStateError()
    
        if 'error' in params:
            raise_from_error(params.get('error'), params)
    
        if not 'code' in params:
            raise MissingCodeError("Missing code parameter in response.")
    
        return params
    

    This line in the parameters file is triggering the error:

    if state and params.get('state', None) != state:
            raise MismatchingStateError()
    

    Since you're using InstalledAppFlow and run_local_server()' I think that the error is linked to your client_secret.json` file.

    I noted in your client_secret.json file that you're using the optional parameter auth_provider_x509_cert_url. According to the API, when using this optional parameter the correct format of client_secret.json file is this:

    {
      "installed": {
        "client_id": "[[INSERT CLIENT ID HERE]]",
        "client_secret": "[[INSERT CLIENT SECRET HERE]]",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://accounts.google.com/o/oauth2/token",
        "client_email": "",
        "redirect_uris": [
          "urn:ietf:wg:oauth:2.0:oob",
          "oob"
        ],
        "client_x509_cert_url": "",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs"
      }
    }