Google Drive API failing. Files:get response CORS error - javascript

I have a web application that relies on saving files to Google Drive and later retrieving them from the server. I am using the Google API Javascript Client and using similar code to the Google Drive API example to retrieve the file. I use a request to the Google API get service to retrieve the file metadata and then I use that file's downloadUrl contained in the metadata to request that file through an XmlHttpRequest, retrieving the access token from the Google API.
getContents = function(fileId,callbackFunction) {
var request = gapi.client.drive.files.get({ fileId : fileId});
request.execute(function(metadata) {
if(metadata.downloadUrl) {
var connection = new haxe.Http(metadata.downloadUrl);
var accessToken = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse(true).access_token;
connection.setHeader("Authorization","Bearer " + accessToken);
connection.async = true;
connection.onData = function(data) {
callbackFunction(metadata,haxe.io.Bytes.ofString(data));
};
connection.onError = function(error) {
callbackFunction(metadata,null);
};
connection.request(false);
}
});
}
As recently as of yesterday, the Google API has stopped working when retrieving files. I can get the file metadata just fine, but when requesting the downloadUrl, it is blocked by the CORS policy because the Google API response does not contain the 'Access-Control-Allow-Origin' header. I have made no changes to the relevant code for a long time, so I am at a loss as to why this suddenly stopped working. Does anyone have any insight as to the source of this problem?

Related

'Bad Request 400' response when getting outlook ics url

I've been running into issues on a legacy project that fetches ical feeds.
I am getting a response of "Bad request 400" when trying to get a calendar via any outlook.office365 url.
I have tested all the urls using PostMan and an online ics validator so I know that it has nothing to do with the calendars themselves not being available.
I am using the npm package 'request' to get the calendars and it's working with any url that doesn't come from the outlook.office365.com host.
For privacy reasons i'm not able to share any of the urls used.
Here is where the request is sent.
async.waterfall([
cb => {
request.get(url, {}, function (err, r, data) {
console.log('response', r.statusCode); // this will be 400 for any outlook.office365 ics url but not for others.
if (err) return cb(err, null);
try {
...
} catch (err) {
...
}
Are there any headers that need to be attached in order to receive outlook.office365 calendars? I can't find anything online about what is required
I had the same issue.
I compared the request headers in Postman and tried to mimic these in my application.
Adding the Postman User Agent string made it work for me:
HttpClient myHttpClient = new HttpClient();
myHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
myHttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("PostmanRuntime","7.30.1"));
var response = myHttpClient.GetAsync(calendarUrl).Result;

Gmail API : Extract "code" param from the URL of a pop-up window to get the access_token details

Iam trying to authenticate gmail using OAuth2 for my web application. From the server, we return a url to the client, which then uses that to open a pop-up. The code is as shown:
var win = window.open(data.google_oauth_url, `<h1>Gmail</h1>`, 'width=800, height=600');
var pollTimer = setInterval(() => {
try {
const searchParams = new URL(win.document.URL).searchParams
console.log("url is",win.document.URL, searchParams, searchParams.get("code"))
if (searchParams.get("code") != -1) {
clearInterval(pollTimer);
win.close();
}
} catch(e) {
console.log("Error",e)
}
}, 500);
From the pop-up , i want to extract the "code" param which google returns to us after the authentication is completed. But when i try to extract the param from the client side, iam facing an error :
Uncaught DOMException: Blocked a frame with origin "https://xyz" from accessing a cross-origin frame
Is anyone aware of a solution for this, or any other ways of extracting the "code" param so i can proceed to get the access_token details.
Thanks in advance.
The above code works, although we face CORS error while authenticating with google, once the authentication is complete, it is redirected to the provided url (web application). And then there is no more cross-origin since the domains are now same.
Ex: https://localhost was your web app url, and the redirect url.
Then it detects the authentication code and once obtained, the pop up closes automatically.

API does not allow origin when requesting from 127.0.0.1:8000

I'm currently developing a website on my localhost. A key component of the website must make requests to a third-party API (specifically https://api.commonstandardsproject.com/). The request is made via javascript running on the user's browser. However, when I attempt to run the following:
var reqUrl = 'https://api.commonstandardsproject.com/api/v1/jurisdictions';
axios.get(reqUrl, {
headers: {
'Api-Key': "vZKoJwFB1PTJnozKBSANADc3"
}
}).then((response) => {
var parsedResp = JSON.decode(response.data)
this.jurisdictions = parsedResp
}).catch((errors) => {
console.log(errors)
});
I receive a 401 from the API and an error stating that: error: "Unauthorized: Origin isn't an allowed origin.". Interestingly, I can access the API content fine (and without an API key) using just a browser or curl. When I check the origin of my request in the networks tab on chrome, it gives 127.0.0.1:8000. I believe this is the locus of the error, though I am uncertain of how to resolve it.
Can anyone tell me how to fix this? Thanks.
I've slightly modified your code to print the result to the browser console.
var reqUrl = "https://api.commonstandardsproject.com/api/v1/jurisdictions";
axios
.get(reqUrl, {
headers: {
"Api-Key": `MY API KEY`,
},
})
.then((response) => {
console.log(response);
})
.catch((errors) => {
console.log(errors);
});
I created an account and found I got the same results as you.
To get a successful response from the api I had to update my 'ALLOWED ORIGINS' in the sidebar of the https://commonstandardsproject.com/developers page to match the first part of the URL from the index.html file I was running in the browser.
E.g. the URL for the index.html I am running locally is:
http://10.0.1.159/index.html
I updated the ALLOWED ORIGINS to include the string
http://10.0.1.159
Allow Origins example
You will have to add the local address for the page you are testing from in the ALLOWED ORIGINS section of the developer page for the commonstandardsproject where you are signed into your account. Make sure to hit the 'update origins' button after you have entered the correct URL.

GraphQL not making request to WP API

Thanks in advance!
I'm pulling data from a WP Rest API and when spin up the wordpress site on my local machine with the address http://localhost:8000 and got to the graphqli playground on http://localhost:3000/api/graphql and i enter a query i get the expected results and i can consume the data happily in react but once i change the WP rest API address to http://example.com/cms i get back an error. The only thing that changes is the URL so i'm guessing it has to do with CORS.
Inspecting the browser window there is no CORS errors so i can rule out CORS being an issue. The strange thing is that when i make the api call via postman i get the response i expect, when i type in the endpoint in a browser i get the results i expect when i use the endpoint to resolve the query request i get an error, so i started to look at the headers as thats the only thing i can see that changes between a postman request and a normal browser request. for the local wp installation # localhost:8000 looking at the logs i can see the request being made from postman and the browser and axios(used in the query resolver) on the flipside the wp installation thats live on the web the logs show the request from postman and from the browser to the api endpoint but not from the graphql resolver. how do i fix this issue with the resolver not making the request?
this is my resolver for the query
const resolvers = {
Query: {
pages: (_parent, _args, _context) => {
return axios.get(`${wpURL}/wp-json/wp/v2/pages`)
.then(res => res.data)
.catch(error => {
console.log("Response Status:", error.response.status);
console.log("Response Headers:", error.response.headers);
console.log("Response Data:", error.response.data);
});
}
}
}
graphqlserver:
import {ApolloServer} from 'apollo-server-micro'
import Cors from 'micro-cors'
import {schema} from './schema'
const cors = Cors()
const server = new ApolloServer({schema})
const handler = server.createHandler({path: '/api/graphql'})
export const config = {
api: {
bodyParser: false,
}
}
export default cors(handler)
terminal:
> next dev
ready - started server on http://localhost:3000
event - compiled successfully
event - build page: /api/graphql
wait - compiling...
event - build page: /api/graphql
event - compiled successfully
page:
What am i doing wrong?
i figured it out it looks like if the endpoint graphql is fetching data from is not secured via SSL it wont even bother asking for data

How to use Google Drive API to download files with Javascript

I want to download files from google drive with javascript API. I have managed to authenticate and load list of files using gapi.client.drive.files request. However, I stuck at downloading those files.
My attempt to download the file:
var request = gapi.client.drive.files.get({
fileId:id,
alt:'media'
});
request.execute(function(resp){
console.log(resp);
});
I have these errors when trying to run the above:
(403) The user has not granted the app 336423653212 read access to the file 0B0UFTVo1BFVmeURrWnpDSloxQlE.
(400) Bad Request
I recognize that the files which aren't google drive file (google doc, google slide) return the 403 error.
I am new to this. Any help and answer is really appreciated.
Update 0
From Google Drive documentation about Handling API Error, here is part of the explanation for 400 errors
This can mean that a required field or parameter has not been provided, the
value supplied is invalid, or the combination of provided fields is
invalid.
This is because I have alt:'media' in my parameter object.
I tried gapi.client.drive.files.export, but it doesn't work either and it returns (403) Insufficient Permission although my Google Drive account has the edit permission for those files. Here is my code:
var request = gapi.client.drive.files.get({
fileId:element.id,
});
request.then(function(resp){
console.log(resp.result);
type = resp.result.mimeType;
id = resp.result.id;
var request = gapi.client.drive.files.export({
fileId:id,
mimeType:type
})
request.execute(function(resp){
console.log(resp);
});
});
Update 1
Based on abielita's answer, I have tried to make an authorized HTTP request but it doesn't download the file. It actually returns the file information in response and responseText attribute in the XMLHttpRequest object.
function test() {
var accessToken = gapi.auth.getToken().access_token;
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.googleapis.com/drive/v3/files/"+'1A1RguZpYFLyO9qEs-EnnrpikIpzAbDcZs3Gcsc7Z4nE', true);
xhr.setRequestHeader('Authorization','Bearer '+accessToken);
xhr.onload = function(){
console.log(xhr);
}
xhr.send('alt=media');
}
______________________________________________________
I found out that I can actually retrieve URLs of all those files from the folder using files' webViewLink or webViewContent attributes.
A file which is from Google Drive type (Google Doc, Google Sheet,
etc...) will have webViewLink attribute. A webViewLink will open
the file in Google Drive.
A non Google Drive type file will have webContentLink. A
webContentLink will download the file.
My code:
var request = gapi.client.drive.files.list({
q:"'0Bz9_vPIAWUcSWWo0UHptQ005cnM' in parents", //folder ID
'fields': "files(id, name, webContentLink, webViewLink)"
});
request.execute(function(resp) {
console.log(resp);
}
Based from this documentation, if you're using alt=media, you need to make an authorized HTTP GET request to the file's resource URL and include the query parameter alt=media.
GET https://www.googleapis.com/drive/v3/files/0B9jNhSvVjoIVM3dKcGRKRmVIOVU?alt=media
Authorization: Bearer ya29.AHESVbXTUv5mHMo3RYfmS1YJonjzzdTOFZwvyOAUVhrs
Check here the examples of performing a file download with our Drive API client libraries.
String fileId = "0BwwA4oUTeiV1UVNwOHItT0xfa2M";
OutputStream outputStream = new ByteArrayOutputStream();
driveService.files().get(fileId)
.executeMediaAndDownloadTo(outputStream);
For the error (403) Insufficient Permission, maybe this is a problem with your access token, not with your project configuration.
The insufficient permissions error is returned when you have not requested the scopes you need when you retrieved your access token. You can check which scopes you have requested by passing your access_token to this endpoint: https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ACCESS_TOKEN
Check these links:
google plus api: "insufficientPermissions" error
Google drive Upload returns - (403) Insufficient Permission
Remember you are uploading to the service accounts google drive account. If you want to be able to see it from your own Google drive account you are going to have to do an insert of the permissions. to give yourself access
Phu, you were so close!
Thank you for sharing your method of using the webContentLink and webViewLink. I think that is best for most purposes. But in my app, I couldn't use viewContentLink because need to be able to enter the image into a canvas, and the image google provides is not CORS ready.
So here is a method
var fileId = '<your file id>';
var accessToken = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse().access_token;// or this: gapi.auth.getToken().access_token;
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.googleapis.com/drive/v3/files/"+fileId+'?alt=media', true);
xhr.setRequestHeader('Authorization','Bearer '+accessToken);
xhr.responseType = 'arraybuffer'
xhr.onload = function(){
//base64ArrayBuffer from https://gist.github.com/jonleighton/958841
var base64 = 'data:image/png;base64,' + base64ArrayBuffer(xhr.response);
//do something with the base64 image here
}
xhr.send();
Notice that I set the response type to arraybuffer, and moved alt=media up to the xhr.open call. Also I grabbed a function that converts the array buffer to base64 from https://gist.github.com/jonleighton/958841.
I found out that I can actually retrieve URLs of all those files from the folder using files' webViewLink or webViewContent attributes. A file which is of Google Drive type (Google Doc, Google Sheet, etc...) will have webViewLink attribute and a non Google Drive type file will have webContentLink. The webViewLink will open the file in Google Drive and the webContentLink will download the file. My code:
var request = gapi.client.drive.files.list({
q:"'0Bz9_vPIAWUcSWWo0UHptQ005cnM' in parents", //folder ID
fields: "files(id, name, webContentLink, webViewLink)"
});
request.execute(function(resp) {
console.log(resp); //access to files in this variable
}
Task: download the file and create File object;
Environment: browser;
const URL = 'https://www.googleapis.com/drive/v3/files';
const FIELDS = 'name, mimeType, modifiedTime';
const getFile = async (fileId) => {
const { gapi: { auth, client: { drive: { files } } } } = window;
const { access_token: accessToken } = auth.getToken();
const fetchOptions = { headers: { Authorization: `Bearer ${accessToken}` } };
const {
result: { name, mimeType, modifiedTime }
} = await files.get({ fileId, fields: FIELDS });
const blob = await fetch(`${URL}/${fileId}?alt=media`, fetchOptions).then(res => res.blob());
const fileOptions = {
type: mimeType,
lastModified: new Date(modifiedTime).getTime(),
};
return new File([blob], name, fileOptions);
};
I was able to download using the files.get API:
var fileId = '<your file id>';
gapi.client.drive.files.get(
{fileId: fileId, alt: 'media'}
).then(function (response) {
// response.body has the file data
}, function (reason) {
alert(`Failed to get file: ${reason}`);
});
let url = https://drive.google.com/uc?id=${file_id}&export=download;
Make sure to pass the file_id in this link.
You can get the file id from the file you want to download by getlink --> general access. Make sure the file is public.

Categories

Resources