clowd function is working finaly but CORS is a pain in the a****

1,218 views
Skip to first unread message

Göran Svensson

unread,
Feb 11, 2020, 5:47:29 PM2/11/20
to Google Cloud Endpoints
Thanks to the great support by Teju Nareddy, to get ESPv2 Beta working, Now I have been working for 5 hours to get access from my React app to the API.

I thought that using my CORS config from render.com that works with my React app would work with the cloud function. So I configured a bay pass of CORS in the open API conf file and wrapped the cloud function in a CORS function. But I still get the same error:

Access to fetch at 'https://rodenedgateway-72pm3i3mfa-uc.a.run.app/user?name=facebook|10157945106394382' from origin 'https://app.rodened.io' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
(anonymous) @ VM933:1
(anonymous) @ Service.js:25
c @ runtime.js:45
(anonymous) @ runtime.js:264
e.<computed> @ runtime.js:98
r @ asyncToGenerator.js:3
s @ asyncToGenerator.js:25
Promise.then (async)
r @ asyncToGenerator.js:13
s @ asyncToGenerator.js:25
(anonymous) @ asyncToGenerator.js:32
(anonymous) @ asyncToGenerator.js:21
(anonymous) @ Service.js:43
(anonymous) @ react-dom.production.min.js:5800
t.unstable_runWithPriority @ scheduler.production.min.js:338
ua @ react-dom.production.min.js:2513
Hs @ react-dom.production.min.js:5547
Ms @ react-dom.production.min.js:4817
(anonymous) @ react-dom.production.min.js:2543
t.unstable_runWithPriority @ scheduler.production.min.js:338
ua @ react-dom.production.min.js:2513
ma @ react-dom.production.min.js:2538
pa @ react-dom.production.min.js:2528
ks @ react-dom.production.min.js:4865
(anonymous) @ react-dom.production.min.js:1783
Service.js:43 TypeError: Failed to fetch



This is How I wrap it in my cloud function  (pseudo-code):

var corsOptions = {
  origin: /rodened\.io$/, // *.rodened.io
  methods: ['POST', 'GET', 'DELETE', 'PUT'],
  credentials: true,
  maxAge: 3600,
  preflightContinue: true,
  optionsSuccessStatus: 200
};

const cors = require('cors')(corsOptions);


exports.sample = functions.https.onRequest((req, res) => {
  cors(req, res, () => {
  HERE IS MY DAMN CODE!
  });
});

But the React app can't read google cloud functions. But the app can read the render.com API function. Both have almost the same CORS config.

what is the best approach to solving it, without wasting all my resources on it? 

I also tried to set it in the ESPv2 but that only coursed deploy errors, so I moved it to the function instead wear I thought that I could solve it by using the same code as in my other API servers.

In my node.js express app, I have one difference from the cloud function, and I don't know if it's important:

Sometimes to make it work you need to add the options before the request. How you do that when you wrap it, I have no clue..

app.options('/update', checkJwt, cors(corsOptions));
app.post('/update', checkJwt, cors(corsOptions), function (req, res) {

An even more frustrated developer...

Göran Svensson

unread,
Feb 11, 2020, 6:06:02 PM2/11/20
to Google Cloud Endpoints
Why should I use ESPv2 Beta when I can get my functions working, and access them without any cors or authentication problem? When I use ESP I get problems after problems, first with deploying for 20 hours, then CORS for 10 hours. It's not productive. To much confusion. Now I don't even know what works or not. Deploying ESP has over 10 steps that are different every time.. Frustrating.

Göran Svensson

unread,
Feb 11, 2020, 6:16:02 PM2/11/20
to Google Cloud Endpoints
The reaon I use cloud function is that I have my db in Firestore. I want to have a managed db instead of a mysql on my own render server. But this is a pain in the a*** like ants in the a***, to make it work. 

Teju Nareddy

unread,
Feb 11, 2020, 6:32:20 PM2/11/20
to Google Cloud Endpoints
Hi Goran,

We are working on a better deployment experience for ESPv2. It will take a while to be in public Beta, but hopefully that will reduce deployment time and increase debuggability.

For CORS, you have 2 options (and it seems like you tried both):
  1. Let your backend handle CORS. If you do then, then you need to tell ESPv2 via the service config to allow all CORS requests to go to your backend. See this document for information in how to configure this, it's just a few lines in your OpenAPI spec. Of course, you will need to redeploy the OpenAPI spec, re-run `gcloud_build_image`, and re-deploy ESPv2 on Cloud Run.
  2. Allow ESPv2 to handle CORS. This is (theoretically) the easier option then having to configure CORS in all your backends. Less coding on your backend. This documentation has more details on which flags you need to set for CORS support. Setting flags is a bit of a pain point due to a limitation on the gcloud CLI. See this document for an example of how to set the CORS flag (the 2nd one with the ++ delimiter). If you follow this approach, all you need to do is re-deploy your Cloud Run service (no need to rebuild the docker image or change the OpenAPI spec).
If you think you are following either of these options correctly, please post your service config, your deployment comment, and any other logs you see so we can help you debug.

Göran Svensson

unread,
Feb 12, 2020, 1:50:26 PM2/12/20
to Google Cloud Endpoints
Yes, I tried both options. 

Tried again with ESPv2 CORS settings:

gcloud run deploy rodenedgateway \
  --set-env-vars=ESPv2_ARGS=^++^--cors_preset=basic++--cors_allow_origin="https://app.rodened.io"++--cors_allow_credentials \
  --allow-unauthenticated \
  --platform managed \
  --project rodened

Works with CURL, but React app tells: 403 error:

Audiences in Jwt are not allowed




Teju Nareddy

unread,
Feb 12, 2020, 2:54:54 PM2/12/20
to Google Cloud Endpoints
Glad the second option is working with CURL.

ESPv2 should handle CORS requests without JWT authentication. Seems like a your React app is sending an incorrect request, perhaps to an incorrect path.

But to better debug this, we need to figure out which request is failing (either the first OPTIONS request, or the 2nd request to the backend). Please open up the developer tools in your browser and look at all network requests made to ESPv2 from your React App. Example: https://developers.google.com/web/tools/chrome-devtools/network/reference

Feel free to share the requests and responses that you see (URL, payload, headers, response status, etc.) in a direct reply to me.

Göran Svensson

unread,
Feb 12, 2020, 2:56:39 PM2/12/20
to Google Cloud Endpoints
This looks strange:

Cloud run log:

2020-02-12 20:41:31.543 CETI0212 19:41:31.523518 2 listener_generator.go:97] adding JWT Authn Filter config: {"name":"envoy.filters.http.jwt_authn","typedConfig":{"@type":"type.googleapis.com/envoy.config.filter.http.jwt_authn.v2alpha.JwtAuthentication","providers":{"auth0_jwk":{"issuer":"https://dev-46fn757m.eu.auth0.com/","audiences":["http://google_api"],"remoteJwks":{"httpUri":{"uri":"https://dev-46fn757m.eu.auth0.com/.well-known/jwks.json","cluster":"dev-46fn757m.eu.auth0.com:443","timeout":"5s"},"cacheDuration":"300s"},"fromHeaders":[{"name":"Authorization","valuePrefix":"Bearer "},{"name":"X-Goog-Iap-Jwt-Assertion"}],"fromParams":["access_token"],"forwardPayloadHeader":"X-Endpoint-API-UserInfo","payloadInMetadata":"jwt_payloads"}},"filterStateRules":{"name":"envoy.filters.http.path_matcher.operation","requires":{"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.User":{"providerAndAudiences":{"providerName":"auth0_jwk","audiences":["http://google_api"]}},"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.Userpost":{"providerAndAudiences":{"providerName":"auth0_jwk","audiences":["http://google_api"]}},"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.Userput":{"providerAndAudiences":{"providerName":"auth0_jwk","audiences":["http://google_api"]}}}}}}

2020-02-12 20:41:31.775 CETI0212 19:41:31.526824 2 listener_generator.go:136] adding Backend Auth Filter config: {"name":"envoy.filters.http.backend_auth","typedConfig":{"@type":"type.googleapis.com/google.api.envoy.http.backend_auth.FilterConfig","rules":[{"operation":"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.User","jwtAudience":"https://us-central1-rodened.cloudfunctions.net/user"},{"operation":"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.Userpost","jwtAudience":"https://us-central1-rodened.cloudfunctions.net/user"},{"operation":"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.Userput","jwtAudience":"https://us-central1-rodened.cloudfunctions.net/user"},{"operation":"1.rodenedgateway_72pm3i3mfa_uc_a_run_app.Webhook","jwtAudience":"https://us-central1-rodened.cloudfunctions.net/webhookPOST"}],"imdsToken":{"uri":"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity","cluster":"metadata-cluster","timeout":"5s"}}}

Göran Svensson

unread,
Feb 12, 2020, 3:00:23 PM2/12/20
to Google Cloud Endpoints
Headers in browser after a GET request to /user

Request Method: GET
Status Code: 403 
Remote Address: 216.239.36.53:443
Referrer Policy: no-referrer-when-downgrade
access-control-allow-credentials: true
access-control-allow-origin: https://app.rodened.io
access-control-expose-headers: Content-Length,Content-Range
alt-svc: quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000
content-length: 32
content-type: text/plain
date: Wed, 12 Feb 2020 19:58:54 GMT
server: Google Frontend
status: 403
x-cloud-trace-context: 7ff74a7f09a8bf45ace5d6f0cb3102b6
:method: GET
:path: /user?name=facebook|10157945106394382
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: sv,en-US;q=0.9,en;q=0.8,sv-SE;q=0.7,it;q=0.6
authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UaENPVVU1UmpNMU5qSTNPRFV4UVRreFFqbEVRamhGT1VVeE9UVTFNMFEyTXpReE16RXdNZyJ9.eyJpc3MiOiJodHRwczovL2Rldi00NmZuNzU3bS5ldS5hdXRoMC5jb20vIiwic3ViIjoiZmFjZWJvb2t8MTAxNTc5NDUxMDYzOTQzODIiLCJhdWQiOlsiaHR0cHM6Ly9ub2RyZWQucm9kZW5lZC5pbyIsImh0dHBzOi8vZGV2LTQ2Zm43NTdtLmV1LmF1dGgwLmNvbS91c2VyaW5mbyJdLCJpYXQiOjE1ODE1Mzc1MjksImV4cCI6MTU4MTYyMzkyOSwiYXpwIjoicEpXZndLeTh2MlFaZzdsWDdSMGp3VWUxeUxSWUdYQ2wiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIn0.EhJqHhrZtsdCZ_qRgrlkNT7KY_N_7igetCPkEvSnw-D75uVytUTA-nSCk63piWtxh1aFbIErfuGxNnch-yNYdBvgKwUzE_ATaK6NQ6a_oPpWB_WZa_y0J8s4y3HJrwpLYGTjztc-JDpMEQbyIXfQ2hjBK19_oSJd-C-BA8UsF0zy0tL58f_seNAwKyQDXZnvvpJNmYvWcShUnqOdcCcnodFXafUFNsu_P8CD46XUanFPTKbUE_T3rTsApRCgPgp-o3eI1bfQgfOBpj99ny6JQ8Eoix5pIdAYN0bX7uk6pGK03ni44bgtsgLbuIeNslUrpQ_MSp_fgXgy_EG3KXgM7g
content-type: application/json
dnt: 1
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36
name: facebook|10157945106394382


Teju Nareddy

unread,
Feb 12, 2020, 3:22:01 PM2/12/20
to Google Cloud Endpoints
Thanks for sharing both logs. Seems like a client side error unrelated to CORS.

The Cloud Run logs are expected.
  • The first log is for JWT Authn, which is for requests from clients. ESPv2 is expecting any clients to have a token with an audience http://google_api.
  • The second log is for Backend Auth. This will allow ESPv2 to talk to your backend Cloud Function with authentication. This is unrelated to the client error.
Based on the web request you shared, the token sent from your React App is incorrect. You can paste your token in jwt.io and look at the "aud" field:

{
  "sub": "facebook|10157945106394382",
  "aud": [
  ],
  "iat": 1581537529,
  "exp": 1581623929,
  "azp": "pJWfwKy8v2QZg7lX7R0jwUe1yLRYGXCl",
  "scope": "openid profile email"
}

I'm not sure how your React app is generating this token. But the audiences do not match. You have a few options:
  • Fix your react app to send the audience expected by ESPv2: http://google_api
  • Modify your service config to put both of those audiences in it (this doesn't follow the Auth0 guide though)

Teju Nareddy

unread,
Feb 12, 2020, 3:24:32 PM2/12/20
to Google Cloud Endpoints
Also, please be careful about posting tokens publicly. It's OK for now since that token does not work. But don't post a working token, as that will allow anyone to access the /userdata API.

Göran Svensson

unread,
Feb 12, 2020, 3:27:08 PM2/12/20
to Google Cloud Endpoints
I think it's auth0 that are not adding the aud correctly.

I login in the React app with auth0 lock panel and it sends back the token which is then use in the app for accesing all API's such as nodered.rodened.io and cloud run. It should add the url for audience http://google_api also.

I can see if it's possible to configure it in the auth0 dashboard. 

Göran Svensson

unread,
Feb 12, 2020, 7:11:44 PM2/12/20
to Google Cloud Endpoints
Yes I know. Will change everything when its working.

Göran Svensson

unread,
Feb 12, 2020, 7:19:18 PM2/12/20
to Google Cloud Endpoints
Ok, I found the reason, Auth0 does not handle multiple audiences by default. So you have to add scopes for read,post,put for different audiences for all your APIs in one of the API configs in auth0's dashboard to make it work and then use this audience from the API config that has the scopes in your app and different api's. So now it's finally working with multiple API requests from the app. I was worried for a while that I had to rebuild the app and use dynamic audiences.



Den onsdag 12 februari 2020 kl. 21:22:01 UTC+1 skrev Teju Nareddy:

qiwz...@google.com

unread,
Feb 12, 2020, 7:35:22 PM2/12/20
to Google Cloud Endpoints
Hi Goran, 

I am glad to hear that finally everything works for you.  Your experience of making auth0, ESPv2 jwt, and  CORS works will be very useful to others. I am wondering if you could capture it here  as an issue so others can benefit. 

Thanks
-Wayne

Reply all
Reply to author
Forward
0 new messages