I'm struggling with this specific step in the Google OAuth process: "Exchange authorization code for tokens" (As called in Google Developers' "OAuth 2.0 Playground", Step 2).
function getGoogleAuthURL() {
const rootUrl = "https://accounts.google.com/o/oauth2/v2/auth";
const options = {
redirect_uri: `http://${HOST}:${PORT}/auth/google`,
client_id: `${googleConfig.clientId}`,
access_type: "offline",
response_type: "code",
prompt: "consent",
scope: defaultScope.join(" "), // A list of scopes declared in the file scope
};
return `${rootUrl}?${querystring.stringify(options)}`;
}
app.get("/auth/google/url", (req, res) => {
res.redirect(getGoogleAuthURL());
});
After redircting the user to the consent prompt, the code above redirect the user to: http://${HOST}:${PORT}/auth/google
, giving the 'Authorization code' necessary to get the refresh and access tokens.
app.get(`/auth/google`, async (req, res) => {
const code = req.query.code
const tokens = await getTokens({code})
});
My problem is coming from the getToken()
function that is used to POST
and return the tokens.
function getTokens({code}) {
const url = 'https://accounts.google.com/o/oauth2/token';
const values = {
code,
client_id: googleConfig.clientId,
client_secret: googleConfig.clientSecret,
redirect_uri: googleConfig.redirect,
grant_type: 'authorization_code',
};
console.log(`${url}${querystring.stringify(values)}`)
return axios
.post(url, querystring.stringify(values), {
headers: {
'Content-Type': 'application/x-www-form-url-encoded',
},
})
.then((res) => res.data)
.catch((error) => {
throw new Error(error.message);
});
}
I get Error: Request failed with status code 401
from the .catch((error) ...
The console.log(${url}${querystring.stringify(values)})
gives the full built link, which is:
https://accounts.google.com/o/oauth2/tokencode=X&client_id=X.apps.googleusercontent.com&client_secret=X&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fdashboard%3B&grant_type=authorization_code
What I troubleshooted:
I've compared many times my 'request' and 'url' with the ones on Google Developers' "OAuth 2.0 Playground", and the syntax doesn't seem to be the problem with the fields, though I have doubt about the punctuation between /token
and code=...
that I changed to /token
and ?code=...
, but still resulting in a failed request (401).
I've also been using two different ${url}
:
https://oauth2.googleapis.com/token
https://accounts.google.com/o/oauth2/v2/auth
But I can tell which one I should be using.
The second param of axios post is the body, not query params.
You can set params in the third argument.
axios.post(url, {}, {
headers: { 'Content-Type': 'application/x-www-form-url-encoded' },
params: {
tokencode: values.code,
// etc
}
}
You are also missing key for code
in your values
object.
You can also just append the querystring in the first argument:
axios.post(url + querystring.stringify(values),{}, {
headers: {
'Content-Type': 'application/x-www-form-url-encoded'
},
})