I have a react app that allows user to pipe in a particular Google Doc that we then analyze the content of. For step 1, picking the document, I'm using this nifty npm package, which also returns to me an "OAuth token", which I presume to be an access_token
I can use to make API calls. I set the returned token and the data returned by the Picker API as state variables in my component, as seen below
<GooglePicker clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}
developerKey={process.env.REACT_APP_GOOGLE_API_KEY}
scope={SCOPES}
onAuthenticate={(token: any) => {
setGoogleToken(token)
}}
onChange={(data: any) => {
setGoogleData(data);
nextOnboardingStage();
}}
onAuthFailed={(data: any) => console.log('on auth failed:', data)}
multiselect={true}
navHidden={true}
authImmediate={false}
mimeTypes={['application/vnd.google-apps.document']}
viewId={'DOCS'}>
<MyCustomButton />
</GooglePicker>
I then try to call the Drive API export function to download said file in this function
const downloadGoogleDoc = async (authToken: string, fileID: string) => {
const res = await axios.get(`https://www.googleapis.com/drive/v3/files/${fileID}/export`, {
headers: {
'Authorization': `token ${authToken}`
}
});
console.log(res);
};
However, I'm getting a 401 error when doing this. Can someone point out where I'm losing the auth? Thanks so much
Edit My entire component is below
const SCOPES = ['https://www.googleapis.com/auth/drive.readonly'];
const Project: React.FC<ProjectInput> = () => {
const [googleToken, setGoogleToken] = useState<string>();
const [googleData, setGoogleData] = useState<any>({});
const [documentData, setDocumentData] = useState();
const downloadGoogleDoc = async (authToken: string, fileID: string) => {
try {
const res = await axios.get(`https://www.googleapis.com/drive/v3/files/${fileID}/export`, {
headers: {
'Authorization': `Bearer ${authToken}`
}
});
console.log(res);
} catch(e) {
console.log(e);
console.log(e.message);
}
};
console.log(googleToken);
console.log(googleData);
const MyCustomButton = () => {
return (
<button className="mx-8 my-2 p-2 rounded bg-blue-500 text-white">
Select From Google Drive
</button>
)
}
if (googleToken && googleData.docs) {
downloadGoogleDoc(googleToken, googleData.docs[0].id);
}
return (
<div className={`ml-${sideBarWidth}`}>
<FadeIn>
<div className="flex flex-col min-h-screen bg-gray-500 py-6 justify-center sm:py-12">
<div className="py-3 sm:max-w-xl sm:mx-auto">
<div className="bg-white min-w-1xl flex flex-col rounded-xl shadow-lg">
<div className="flex">
<div>
<div>
<div className="px-8 py-5">
<h2 className="text-gray-800 text-3xl font-semibold">Great! Select the document you'd like us to scan</h2>
</div>
</div>
<GooglePicker clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}
developerKey={process.env.REACT_APP_GOOGLE_API_KEY}
scope={SCOPES}
onAuthenticate={(token: any) => {
setGoogleToken(token)
}}
onChange={(data: any) => {
setGoogleData(data);
nextOnboardingStage();
}}
onAuthFailed={(data: any) => console.log('on auth failed:', data)}
multiselect={true}
navHidden={true}
authImmediate={false}
mimeTypes={['application/vnd.google-apps.document']}
viewId={'DOCS'}>
<MyCustomButton />
</GooglePicker>
</div>
</div>
</div>
</div>
</div>
</FadeIn>
</div>
);
};
export default Project;
EDIT
As @Tanaike said, I needed to include MimeType in my request, working function is below
const downloadGoogleDoc = async (authToken: string, fileID: string) => {
try {
const params = new URLSearchParams([['mimeType', 'text/html']]);
const res = await axios.get(`https://www.googleapis.com/drive/v3/files/${fileID}/export`, {
params,
headers: {
'Authorization': `Bearer ${authToken}`
}
});
console.log(res);
} catch(e) {
console.log(e);
console.log(e.message);
}
};
I believe your goal and your situation as follows.
401
.mimeType
for exporting is required to be used.When I saw your following script, I noticed a modification point except for endpoint.
const res = await axios.get(`https://www.googleapis.com/drive/v3/files/${fileID}/export`, {
headers: {
'Authorization': `token ${authToken}`
}
});
token
is not correct. Please modify it to Bearer
. I thought that this is the reason of the error 401
.When catch
is used, the error message can be retrieved.
If you download a binary file, the binary data is directly retrieved. At that time, when responseType: 'arrayBuffer'
and responseType: 'blob'
are used, the data is retrieved as array buffer and blob, respectively.
When above points are reflected to your script, it becomes as follows.
const res = await axios.get(`https://www.googleapis.com/drive/v3/files/${fileID}/export`, {
headers: {
'Authorization': `token ${authToken}`
}
});
To:
const mimeType = "###"; // Please set the mimeType.
const res = await axios.get(`https://www.googleapis.com/drive/v3/files/${fileID}/export?mimeType=${mimeType}`, {
// responseType: `arrayBuffer`, // or 'blob'
headers: {
'Authorization': `Bearer ${authToken}`
}
}).catch(err => console.log(err.response));
console.log(res); // or res.data
In this modified script, it supposes that your access token can be used for downloading the file from Google Drive. So please be careful this.
When you use the method of "Files: export", please use the Google Docs files as the file ID. Please be careful this. Ref