cors issue on github oauth - javascript

import request from 'superagent';
const self = this;
request
.post('https://github.com/login/oauth/access_token')
.set('Content-Type', 'multipart/form-data')
.query({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
callback: 'http://127.0.0.1:3000/callback',
code,
state,
})
.end((err, res) => {
const token = res.body.access_token;
console.log(token);
self.setToken(token);
});
The code above will give me an error like this
XMLHttpRequest cannot load
https://github.com/login/oauth/access_token?client_id=112asdecf3805fdada12&…127.0.0.1%3A3000%2Fcallback&code=434ebd7bb98d9809bf6e&state=HelloWorld1234.
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:3000' is therefore not allowed
access.
I have no idea why even though I've registered the oauth application with github and callback url is http://127.0.0.1:3000/callback

While all the actual GitHub API endpoints support CORS by sending the right response headers, it is a known issue that the https://github.com/login/oauth/access_token endpoint for creating an OAuth access token does not support CORS requests from Web applications.
The very specific workaround for this case is to use https://github.com/prose/gatekeeper:
Gatekeeper: Enables client-side applications to dance OAuth with GitHub.
Because of some security-related limitations, Github prevents you from implementing the OAuth Web Application Flow on a client-side only application.
This is a real bummer. So we built Gatekeeper, which is the missing piece you need in order to make it work.
The general workaround is: Use an open reverse proxy like https://cors-anywhere.herokuapp.com/
var req = new XMLHttpRequest();
req.open('POST',
'https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/access_token',
true);
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send('code=' + encodeURIComponent(location.query.code) +
'&client_id=foo' +
'&client_secret=bar');
...
See also How to use Cors anywhere to reverse proxy and add CORS headers.

Related

Uploading a video to the presigned URL from Frontend

I have used my backend code to generate the presigned URL and then used that URL to upload a video that was recorded during the session. I am using the below piece of code in the frontend(React JS) to upload the video the preflight seems to fail with 403 Forbidden and the post request fails with cors error. Please find below the details:
Code used:
static async uploadVideoToS3(url, body) {
try {
const myHeaders = new Headers({ 'Content-Type': 'video/mp4', 'mode': 'no-cors' });
const response = fetch(url, {
method: 'POST',
headers: myHeaders,
body: body
});
return response;
} catch (error) {
toast(error);
console.log(error);
}
}
Console error:
Access to fetch at 'https://xxxxxxxxxx' from origin 'http://localhost:5000' 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.
Note: Changed the presigned URL to xxxxxxxxxx to avoid leaking the details in the post here.
Could the issue be that I am running all this on localhost? Or Is the CORS Configuration on the AWS S3 Bucket causing this issue? or Is there any header missing in my request?
I found a post that had a similar issue: Getting 403 (Forbidden) when uploading to S3 with a signed URL where the OP responded that the issue was resolved but they never mentioned the resolution.
Try adding proxy to package.json file and add the url of the server you're sending your request to, In your case localhost:5000
"proxy": "http://localhost:5000"
Then restart your app with npm start and change the url in your component, if you are doing it like
const res = fetch('https://localhost:5000/api/user')
then change it and do it like below
const res = fetch('/api/user')
If the above solution doesn't work then there might be a problem with your backend.
I thought so too that as I was trying to hit the URL from local which isn't served on a secure host (HTTP) was causing the issue. So I deployed the app on a dev environment but faced the same issue. After some research, I was able to fix the issue. It seems that I needed to modify the CORS configuration of the S3 Bucket that I was trying to generate the pre-signed URL from.
Before generating the pre-signed URL, I added the below piece of code which changes the CORS configuration of the S3 bucket and since I was accessing it from my local as well I have put the Allowed Origins as * for now but before moving to production, I will change it to the prod URL.
//passing AWS credentials
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(clientRegion)
.build();
//Creating CORS List to update the CORS Configuration
List<String> allowedHeaders=new ArrayList<String>();
allowedHeaders.add("*");
List<AllowedMethods> allowedMethods=new ArrayList<AllowedMethods>();
allowedMethods.add(0, AllowedMethods.GET);
allowedMethods.add(1, AllowedMethods.PUT);
List<String> allowedOrigins=new ArrayList<String>();
allowedOrigins.add("*");
List<String> exposedHeaders=new ArrayList<String>();
exposedHeaders.add("GET");
exposedHeaders.add("PUT");
CORSRule cors = new CORSRule();
cors.setAllowedHeaders(allowedHeaders);
cors.setAllowedMethods(allowedMethods);
cors.setAllowedOrigins(allowedOrigins);
cors.setExposedHeaders(exposedHeaders);
cors.setMaxAgeSeconds(3600);
//Assigning CORS List to CORS Configuration
BucketCrossOriginConfiguration CORSConfiguration = new BucketCrossOriginConfiguration();
CORSConfiguration.withRules(cors);
//Updating CORS Configuration
s3Client.setBucketCrossOriginConfiguration(bucketName, CORSConfiguration);
Alternatively, you can modify the CORS from the frontend/other languages as well, reference:
Javascript: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putBucketCors-property
Other Languages: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html#API_PutBucketCors_SeeAlso

Cannot call Apache Airflow REST API using JavaScript Fetch API (CORs Error)

Working with Apache Airflow REST API, and having issues with CORS.
When calling the endpoint using the fetch API in JavaScript I get the following error:
Access to fetch at 'my_url/api/v1/dags/example_bash_operator/tasks' from origin 'my_url' 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.
This is how I am calling it:
let url = "my_url/api/v1/dags/example_bash_operator/tasks";
let username = 'my_username';
let password = 'my_password';
let headers = new Headers();
headers.set('Authorization', 'Basic ' + btoa(username + ":" + password));
fetch(url, {
headers: headers,
method: 'GET',
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
I also tried adding mode: 'no-cors' but just get the "unexpected end of input" error.
For some background, the following works fine:
starting the airflow webserver and scheduler
accessing the airflow UI
accessing the SwaggerUI authenticating Swagger and calling the REST endpoints with this tool
calling my_url in the address bar of a new browser tab (returns the expected JSON)
I have set the auth_backend in airflow.cfg:
auth_backend = airflow.api.auth.backend.default
Although with the latest REST API version I don't think this makes a difference since everything is set to deny.
I have also set the access control headers in airflow.cfg as described in the docs:
access_control_allow_headers = origin, content-type, accept
access_control_allow_methods = POST, GET, OPTIONS, DELETE
access_control_allow_origin = my_url
...and also tried with wildcard for the access_control_allow_origin:
access_control_allow_origin = *
So the REST calls work fine through Swagger and through the browser address bar, but I cannot call it with fetch using JS. Note that the JS is in an index.html file on the same server (and same root directory) as the airflow files.
The described behavior makes sense, since CORS is used by the browser to prevent attacks from scripts of different resources.
You are still able to fetch via Swagger, Postman or other tools, even through the browser via address bar. But if the policy does not allow to fetch from a different origin, then the browser prevents fetching from your script, which is probably served on a different port. Origin contains host and port.
Your main issue, I cannot help with at the moment.
I've faced the issue of not being able to set the origin policy within the Airflow 2.0 server/API through the (docker-compose) environment variable AIRFLOW__API__ACCESS_CONTROL_ALLOW_ORIGIN.
Maybe it's related to your issue, since I can see from the url of your question (containing the v1), that you're are also using Airflow 2.x.
By the way, the message from chrome is CORS error: Preflight Missing Allow Origin Header, referring to the question in the comments of the original question.

Keycloak Introspection Endpoint

I'm trying to access to introspect endpoint in my Keycloak server /openid-connect/token/introspect from my front app, but I get next error:
Access to fetch at 'http://localhost:8180/auth/realms/backoffice/protocol/openid-connect/token/introspect' from origin 'http://localhost:8080' 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.
Using Postman, curl or Node app this request works fine, but from my front-app using fetch method thows this error. I'm not sure it's possible query for introspect endpoint from front-app in the browser or if it's only possible from server app.
Other endpoints like:
openid-connect/token:
openid-connect/userinfo:
Works fine using the Postman JS code.
Keycloak config
My client in Keycloak has set up Web Origins * and Access Type confidential.
Client Code
My front app is simply the Postman code JS, and I deploy it using node http-server.
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("client_id", "my-client");
urlencoded.append("client_secret", "my-secret");
urlencoded.append("token", "eyJ...oCA");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost:8180/auth/realms/backoffice/protocol/openid-connect/token/introspect", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
Header Response
The header response in userinfo endpoint comes with Access-Control-Allow-Origin and Access-Control-Allow-Credentials but is not present in introspect endpoint.
From the looks of it, the Keycloak server prevents the CORS headers to be set for the introspection endpoint. This could be a bug or by design. I tried it and I get the same error.
If you really want to access the introspect endpoint from the web app, you could set up a NGINX reverse-proxy in front of your Keycloak server and use it to add the missing headers.
That being said, according to oauth.com you should not leave the introspection endpoint available to the public, which is what you are currently doing since anyone can retrieve the client id and secret from your web app.
If the introspection endpoint is left open and un-throttled, it presents a means for an attacker to poll the endpoint fishing for a valid token. To prevent this, the server must either require authentication of the clients using the endpoint, or only make the endpoint available to internal servers through other means such as a firewall.
This could explain the decision not to allow CORS.
Another thing, it looks like you forgot to set the token_type_hint check out this stackoverflow post for more information.

Binance API and angular 4 httpClient

I have a question about cryptomarket Binance.
They have public api which I though I could use in angular to create trading app.
But I have some troubles.
Using that link in chrome I get json result.
https://api.binance.com/api/v1/exchangeInfo
But using with angular 4 httpClient:
this.http.get('https://api.binance.com/api/v1/exchangeInfo').subscribe(res => console.log(res));
I have error: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at api.binance.com/api/v1/exchangeInfo. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
It doesn't work. I don't get it, why I can't use that API in angular app?https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md
What should I do?
Should I set headers like that:
getMarkets() {
const headers = new HttpHeaders();
headers.set('Content-Type', 'application/json');
headers.set('Accept', 'application/json');
headers.set('Access-Control-Allow-Headers', 'Content-Type');
headers.set('Access-Control-Allow-Origin', '*');
const path = 'https://api.binance.com/api/v1/exchangeInfo';
return this.http.get(path, {headers: headers});
}
Thanks in advance
You can't quite use it directly like that, Binance API does not set CORS headers, so Chrome and all major browsers will block the requests.
There is a bit more to it, but essentially, the api servers that need to enable support for CORS should set Access-Control-Allow-Origin to be * or a single domain www.example.com, this allows the browsers to prevent malicious code on a site to call and read the response of some data from other site you might be logged on to ( eg: bank info )
You can read more about it here
One possible solution is to have your own server that proxies calls to binance
Another solution if you're testing things out is to use a CORS enabling extension like this one
Update: You can also use the websocket API if that satisfies your data needs docs
Update 2: Here's a good stackoverflow question on cors
Side note: If your bank's API server sets the Access-Control-Allow-Origin to * then change banks :)
Try this simple request without headers.
this.http.get('https://api.binance.com/api/v1/exchangeInfo').subscribe(data => {
this.results = data;
});
}
It work for me
HttpHeaders is immutable. So you must write
const headers = new HttpHeaders().
set('Content-Type', 'application/json').
set('Accept', 'application/json').
set('Access-Control-Allow-Headers', 'Content-Type').
set('Access-Control-Allow-Origin', '*');
or
const headers = new HttpHeaders(
{
Content-Type:'application/json'),
Accept:'application/json'),
Access-Control-Allow-Headers:'Content-Type'),
Access-Control-Allow-Origin:'*')
})

CORS not working with Uber API OAuth endpoints

I am trying to make client-side JS calls to Uber API endpoints which require the OAuth Bearer token, such as /v1/me, but I am receiving an error that the Access-Control-Allow-Origin header is not present on the response.
I have successfully obtained a Bearer token (server-side) to use in the Authorization header in the GET request.
In my Uber API application settings, I have my Origin URI set to my development server (https://localhost:9000).
Here is how I call the /v1/me endpoint:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.uber.com/v1/me');
xhr.setRequestHeader("Authorization", "Bearer MY_BEARER_TOKEN");
xhr.send();
In Chrome developer console I get the following error:
No 'Access-Control-Allow-Origin' header is present on the requested resource
To ensure that my Bearer token is valid, I successfully tested it using curl:
curl -H 'Authorization: Bearer MY_BEARER_TOKEN' 'https://api.uber.com/v1/me'
On a side note, I am able to successfully make calls to the API endpoints which do NOT require OAuth Bearer token, such as /products and /estimates/price using the Authorization Token header like so:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.uber.com/v1/products');
xhr.setRequestHeader("Authorization", "Token MY_SERVER_TOKEN");
xhr.send();
This leads me to believe that the problem is not an Uber API app configuration setting such as incorrect Origin URI.
One final note, when I obtain the OAuth token I am making the request from a Node Express app running on my development server at https://localhost:8080, which is different from where I am running my client-side JS app at https://localhost:9000. Making the request from the same port did not solve the problem however.
Any ideas? Thanks!
Are you using an iFrame anywhere in your app? That problem usually comes up when I'm requesting to use an iFrame with a product that doesn't normally allow people to do so.
After emailing with Uber tech support, the problem was that CORS was not properly setup on their end. As of yesterday the /v1/me endpoint is now working for me with no changes to my app configuration.

Categories

Resources