Ajax request to cloud run service that requires authentication - ajax

I'm having a CORS related issue with google cloud run on a service that
requires authentication.
If I try to execute a curl command through the cli, with a Bearer token,
everything works fine.
Unfortunately if I try to execute the same call through ajax in javascript,
I receive a 403.
const http = new XMLHttpRequest();
const url = 'https://my-app.run.app';
http.open("GET", url);
http.withCredentials = true;
http.setRequestHeader("authorization", 'Bearer ' + id_token);
http.send();
http.onreadystatechange = (e) => {
console.log(http.responseText)
}
The error in the cloud run logs is this :
The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating
The container is never hit.
The issue I'm seeing is that, as I'm making the call using ajax, in a web
browser. The web browser is making a pre flight request ( OPTIONS on the
url ) without sending the Authorization header ( which is an expected
behavior )
The problem seems to be that cloud run tries to authenticate the OPTIONS
request and never makes it to my container, which, as far as I understand,
shouldn't be done. (
https://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0 )
Is that a known issue with cloud run ?
How could I make an ajax request to an authenticated cloud run service ?

(Cloud Run PM)
This is a known issue. There are a few options:
Allow unauthenticated requests and do CORS/auth yourself
There is a variation of this that uses Cloud Endpoints running on Cloud Run in front of your compute. Have Endpoints do your end-user auth, then forward the request to your backend.
Serve from the same domain (e.g. use the Firebase Hosting proxy)
We've considered implementing Istio CORSPolicy, which would return CORS headers before the auth check, though we're not committed to this as of now.

Related

Intermittent CORS issue with FastAPI deployed on Heroku

I deployed a FastAPI based backend on Heroku and whenever I query the url via cURL or Postman, it works fine. However, when it queried from a chrome extension (built on React for Github), it throws
Access to fetch at '<API>' (redirected from '<API>') from origin 'https://github.com' has been blocked by CORS policy: 'No-Access-Control-Allow-Origin' header is present on the requested resource.
Funny thing is that the request runs fine for most of the time but when the server is not queried for about 10 mins, it first throws this error 2-3 times then the subsequent requests succeed.
From the frontend, Javascript fetch API is used to query the API with method & Content-type header.
To set up CORS policy on backend, I followed this CORS docs. Following is the snippet:
app = FastAPI()
origins = [
"https://github.com",
"http://localhost:8000" # dev
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
I am not able to understand if this issue is from frontend, backend or Heroku free dyno going to sleep. Thanks.
The request to your API is most likely coming from "Origin": "chrome-extension://..."
You can change your FastApi controller to
origins = ["*"]
That should give you a temporary fix.
As far as adding your specific Chrome extension to the allowed origins ...that's what I'm on here searching for lol.

Is there a potential data leak when redirecting from http to https?

I have the following code in my Fastify server hosted on Heroku:
this.server.addHook('preHandler', async(req, reply) => {
const isHttps = req.headers['x-forwarded-proto'] === 'https';
if (isHttps) {
return;
}
const {
method,
url
} = req;
if (method && ['GET', 'HEAD'].includes(method)) {
const host = req.headers.host || req.hostname;
reply.redirect(301, `https://${host}${url}`);
}
});
The idea is to prevent access to the server through HTTP and force redirection to HTTPS at the application-level, since it is not possible otherwise on Heroku.
My question is: if the first request to the server via HTTP (before the redirection happens) contains sensitive information such as a username/password, wouldn't that still be "dangerous" or compromising somehow?
You have probably mis-configured something on Heroku.
Heroku domains (.herokuapp.com) are by default HTTPS enabled. The same page has a guide for custom domain SSL setup guide. Since you are talking about (username + password), I am going to assume this is a website. All you need to do is setup CORS with fastify-cors. Your website should ALWAYS be served over HTTPS.
Also you should not use the logic above. Fastify isn't meant to be used as a proxy server. The docs strongly suggest using a front-facing proxy server like nginx. With Heroku you don't need all these. It already handles this for you.
In the future you could also use Cloudflare as a "proxy server" outside Heroku.

Google APIs OAuth refresh token url return 401 on http redirect uri?

I had implemented the code to received authorization code as described in this step:
https://developers.google.com/android-publisher/authorization#generating_a_refresh_token
We deployed this code to one server that has "https://..." domain and this works well. We can get the access_token, refresh_token...
But now we need to deploy the same code to a dev server that has no "https".
I created a new OAuth client id with redirect uri using the dev server (no https, the rest /api/v1/... is the same as the previous working server)
Now anytime I tried to go to this url and Allow access
https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=http://dev_server/api/v1/...&client_id=dev_server_client_id
I got 401 Unauthorized.
I'm not sure why, but the only difference I can see is "https" vs "http".
Any idea why?
Thank you very much.
Actually I forgot to update the corresponding values in my code
const oauth2Client = new OAuth2(
config.googleApi.clientId,
config.googleApi.clientSecret,
config.googleApi.redirectUri // <= Especially this value
);
These values need to be updated to (beside values on google console).

Create function in Parse Cloud Code that does not require authorisation

I have my own instance of Parse Server running on AWS and until now Cloud Functions have been working great, but with one caveat: they cannot be successfully called publicly, i.e. they require an authorisation key be sent in the REST request header.
I want to set up a Slack Slash Command to my server, and it has to be able to POST a payload without any headers or extra parameters. As a result, my requests are currently unauthorised (returning 403 statuses).
Is there a way to create granular control over a Parse Cloud Function's authorisation (i.e. if it requires master-key header or not), and if not — is there a way of forwarding the request but still through the Parse server?—Or even a way of manipulating the headers of a Slack request? I would rather not have to use another service just for request forwarding.
Thanks!
Two options
Pass in the master key on the client request which should bypass authorization. It's a blunt approach but might be okay in your case (without knowing more details).
Or run a new express endpoint alongside parse and from there call the parse cloud function using the masker key.
var api = new ParseServer(...)
var app = express();
app.use('/parse', api);
app.get('/api/slack', function(req, res) {
//call cloud function passing in master key
// add X-Parse-Master-Key as http header
unirest.post("http://myhost.com:1337/parse/functions/mycloudfunction")
.headers({'X-Parse-Master-Key', MASTER_KEY)
.end(function(response) {
}

Providing auth header with SockJS

I have a Spring MVC server that provides a bunch of REST endpoints as well as a websocket endpoint. Everything except the login endpoint requires authentication. I'm using JWT to authenticate requests coming from the client.
When the user logs in I'm returning an X-AUTH-TOKEN header, containing the JWT token. This token is then passed in the same header on every request to the server. This all works fine for the REST endpoints, but I can't figure out how to do this on the websocket.
I'm using SockJS, and when I open the connection:
var socket = new SockJS('/socket/updates', null, {});
This causes a GET request to /socket/updates/info?t=xxx which returns a 403 (as everything requires auth by default).
Ideally I'd simply send my X-AUTH-TOKEN header on any XHR requests SockJS makes, but I can't see any way of adding headers looking at the API.
Worst case I can change SockJS to do this, but I'm wondering whether this functionality has been deliberately left out? I know SockJS doesn't support cookies for security reasons but that's not what I'm trying to do.
Also, for the sake of a test I did allow the info endpoint to have anonymous access but then it 403's on a bunch of other endpoints - it feels more elegant to simply pass in auth details on these requests than poke holes in my server security.
Any help appreciated.
Cheers
You cannot set the header from SockJS. Not because SockJS does not have this functionality, but because browser makers don't expose this API to Javascript. See:
https://github.com/sockjs/sockjs-client/issues/196
For a workaround, see JSON Web Token (JWT) with Spring based SockJS / STOMP Web Socket.
client side:
stompClient.connect({headername:header}, function () {
setConnected(true);
stompClient.subscribe(request.topic, function (message) {
output(message.body);
});
});
server side :
StompHeaderAccessor accessor
= MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
String headervalue= accessor.getNativeHeader("your header name").get(0);

Resources