title: Configuring Auth0 authentication on Google App Engine Standard and the Cloud Endpoints Frameworks with Python
body: <p>I am using <a href="https://cloud.google.com/endpoints/docs/frameworks/python/about-cloud-endpoints-frameworks" rel="nofollow noreferrer">Cloud Endpoints Frameworks with Python</a> in a Google Cloud App Engine Standard environment to provide an API.</p>
  
  <p>As far as I can tell, I should be able to use python decorators from the Endpoints Frameworks in combination with the endpointscfg.py command-line tool to automatically set up token-based authentication with Auth0; the endpointscfg.py command-line automatically creates the openapi.json file that is used to configure the Google Endpoints proxy.</p>
  
  <p>Here's an example of my decorator for an API that echos stuff back:</p>
  
  <pre><code># # [START echo_api]
  @endpoints.api(
      name='echo',
      version=_VERSION,
      api_key_required=True,
      audiences={'auth0': ['https://echo.&lt;my-project&gt;.appspot.com/_ah/api/echo/v1/echo']},
      issuers={'auth0': endpoints.Issuer(
          'https://&lt;my-project&gt;.auth0.com',
          'https://&lt;my-project&gt;.auth0.com/.well-known/jwks.json')}
  )
  class EchoApi(remote.Service):
      ...
  </code></pre>
  
  <p>When I run the endpointscfg.py command-line tool, I get something in my openapi.json file that looks about right:</p>
  
  <pre><code>"paths": {
      "/echo/v1/echo": {
        "post": {
          "operationId": "EchoApi_echo",
          "parameters": [
            {
              "in": "body",
              "name": "body",
              "schema": {
                "$ref": "#/definitions/MainEchoRequest"
              }
            }
          ],
          "responses": {
            "200": {
              "description": "A successful response",
              "schema": {
                "$ref": "#/definitions/MainEchoResponse"
              }
            }
          },
          "security": [
            {
              "api_key": [],
              "auth0_jwt": []
            }
          ]
        }
      }
  
  "securityDefinitions": {
      "api_key": {
        "in": "query",
        "name": "key",
        "type": "apiKey"
      },
      "auth0_jwt": {
        "authorizationUrl": "https://&lt;my-project&gt;.auth0.com/authorize",
        "flow": "implicit",
        "type": "oauth2",
        "x-google-issuer": "https://&lt;my-project&gt;.auth0.com",
        "x-google-jwks_uri": "https://&lt;my-project&gt;.auth0.com/.well-known/jwks.json",
        "x-google-audiences": "https://echo.&lt;my-project&gt;.appspot.com/_ah/api/echo/v1/echo"
      }
    }
  </code></pre>
  
  <p>So, the problem is that this set-up appears to do nothing and does not check incoming tokens to prevent access if no token is present or if the token is invalid.</p>
  
  <p>I have been able to set-up manual processing of the bearer token within the API echo function using the python-jose library (sorry if it's not well done, but I'm just testing and comments are welcome):</p>
  
  <pre><code>authorization_header = self.request_state.headers.get('authorization')
      if authorization_header is not None:
          if authorization_header.startswith('Bearer '):
              access_token = authorization_header[7:]
              logging.info(access_token)
          else:
              logging.error("Authorization header did not start with 'Bearer '!")
              raise endpoints.UnauthorizedException(
                      "Authentication failed (improperly formatted authorization header).")
          else:
              logging.error("Authorization header did not start with 'Bearer '!")
              raise endpoints.UnauthorizedException("Authentication failed (bearer token not found).")
  
  r = urlfetch.fetch(_JWKS_URL)
  jwks_content = json.loads(r.content)
  keys = jwks_content['keys']
  public_key = jwk.construct(keys[0])
  logging.info(public_key)
  
  message, encoded_signature = str(access_token).rsplit('.', 1)
  # decode the signature
  decoded_signature = base64url_decode(encoded_signature.encode('utf-8'))
  # verify the signature
  if not public_key.verify(message.encode("utf8"), decoded_signature):
      logging.warning('Signature verification failed')
      raise endpoints.UnauthorizedException("Authentication failed (invalid signature).")
  else:
      logging.info('Signature successfully verified')
  
  claims = jwt.get_unverified_claims(access_token)
  # additionally we can verify the token expiration
  if time.time() &gt; claims['exp']:
      logging.warning('Token is expired')
      raise endpoints.UnauthorizedException("Authentication failed (token expired).")
  # and the Audience  (use claims['client_id'] if verifying an access token)
  if claims['aud'] != _APP_CLIENT_ID:
      logging.warning('Token was not issued for this audience')
      raise endpoints.UnauthorizedException("Authentication failed (incorrect audience).")
  # now we can use the claims
  logging.info(claims)
  </code></pre>
  
  <p>This code works, but I assumed that the whole point of setting up the decorator and configuring the openapi.json file was to off-load these checks to the proxy so that only valid tokens hit my code.</p>
  
  <p>What am I doing wrong?</p>
  
  <p><strong>UPDATE:</strong>
  It may be that I need to check endpoints.get_current_user() in my code to control access. However, I have just noticed the following in my logs:</p>
  
  <pre><code>Cannot decode and verify the auth token. The backend will not be able to retrieve user info (/base/data/home/apps/e~&lt;my-project&gt;/echo:alpha23.414400469228485401/lib/endpoints_management/control/wsgi.py:643)
  Traceback (most recent call last):
    File "/base/data/home/apps/e~&lt;my-project&gt;/echo:alpha23.414400469228485401/lib/endpoints_management/control/wsgi.py", line 640, in __call__
      service_name)
    File "/base/data/home/apps/e~&lt;my-project&gt;/echo:alpha23.414400469228485401/lib/endpoints_management/auth/tokens.py", line 75, in authenticate
      error)
  UnauthenticatedException: (u'Cannot decode the auth token', UnauthenticatedException(u'Cannot find the `jwks_uri` for issuer https://&lt;my-project&gt;.auth0.com/: either the issuer is unknown or the OpenID discovery failed',))
  </code></pre>
  
  <p>However, I think everything is configured ok. Any idea why 'jwks_uri' cannot be found despite the fact that path in the openapi.json file is correct?</p>