Google redirect uri missmatch - server back-end auth code exchange to Access Token - google-api

I try to build below:
by following: this steps
and i use oauth playground to generate auth code and load it into my server manually (for testing purpose)
i did put in Authorised redirect URIs : https://developers.google.com/oauthplayground and try to get my auth code this way.
then i load my auth code generated from playground to my REST API Server (http://localhost:5000/api/user/blah) and use this python snippet to exchange the code:
try:
credentials = client.credentials_from_clientsecrets_and_code(
app.config.get('GG_APP_SECRET'),
['https://www.googleapis.com/auth/plus.me', 'profile', 'email'],
req_gg_code)
except Exception as e:
log.info('>>>>> Exception: %s <<<<<', e)
return generate_response(code=400, error=False, type='Fail', message=str(e))
and the result: i keep receive error:
oauth2client.client - INFO - Failed to retrieve access token: b'{\n
"error" : "redirect_uri_mismatch"\n}'
my REST API server doesnt have any interface, it will just receive feed from other client (e.g. mobile app) and it doesnt have any redirect uri.
so what's wrong here? what is the correct configuration of my web client id?
at the moment i'm using web client id (type: web application) with redirect uri: https://developers.google.com/oauthplayground

Related

Google Identity for server-side web app - redirect URI mismatch

I'm attempting to set up the Code Model for Google authentication, so that my user can oauth with Google and my app can retrieve their Calendar data. I'm stuck on step 5 here, where I'm supposed to exchange the authorization code for refresh and access tokens. I'm using nestjs in the backend and React in the frontend.
What I've done already that's working:
User clicks a button on my web app's page
Client sets up google.accounts.oauth2.initCodeClient with the /calendar scope, in ux_mode: popup
User is shown the Google popup and can auth thru that
Client receives a response from Google containing the authorization code
Client makes a POST call to my backend to send it just that authorization code
In step 5, the client makes the POST call to localhost:4000/auth/google-test. In the backend, I'm using the googleapis package and have:
export const oauth2Client = new google.auth.OAuth2(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
'http://localhost:4000/' // <- note, I'm not sure if this is corect
);
And in the relevant controller route, I'm doing:
#Post('google-test')
public async googleTest(#Body() bodyReceived: any): Promise<any> {
let { code } = bodyReceived
let { tokens } = await oauth2Client.getToken(code)
oauth2Client.setCredentials(tokens);
console.log('Tokens: ' + tokens);
return
The error I'm getting is related to oauth2Client.getToken(code), and the error is a redirect_uri_mismatch. In GCP for the credentials for this app, I've added all of these as "Authorized redirect URIs":
http://localhost:3000/home
http://localhost:4000/auth/google-test
http://localhost:4000
What am I doing wrong?
It took a bit more Googling, but turns out that the right answer is to have my server make the token call with the redirect uri as "postmessage".
This SO question gives a bit more context. A somewhat unbelievable message, but it seems to work for my app.
It is evidently that what is happening is that the redirect URI does not match with the one in the GCP. This usually happens because backend tools such as Nestjs may be appending a trailing '/' to the URL and it may be interpreted as being part of the redirect_uri value.
You can try by temoving any trailing '/' via this following method oauthurl.replace(/\/$/, '')
Moreover, you can pass the generated auth URL to a meta tag. And check the html header to confirm what is the URL value.

Facebook Oauth2 authentication not working for spring boot application

I am building a spring-boot application which uses google/facebook oauth2 authentication. The application configurations set are as follows:
#Google
spring.security.oauth2.client.registration.google.clientId=<googleClientId>
spring.security.oauth2.client.registration.google.clientSecret=<googleClientSecret>
spring.security.oauth2.client.registration.google.redirectUri={baseUrl}/oauth2/callback/{registrationId}
spring.security.oauth2.client.registration.google.scope=email,profile
#Facebook
spring.security.oauth2.client.registration.facebook.clientId=<fbClientId>
spring.security.oauth2.client.registration.facebook.clientSecret=<fbClientSecret>
spring.security.oauth2.client.registration.facebook.redirectUri={baseUrl}/oauth2/callback/{registrationId}
spring.security.oauth2.client.registration.facebook.scope=email,public_profile
spring.security.oauth2.client.provider.facebook.authorizationUri=https://www.facebook.com/v13.0/dialog/oauth
spring.security.oauth2.client.provider.facebook.tokenUri=https://graph.facebook.com/v13.0/oauth/access_token
spring.security.oauth2.client.provider.facebook.userInfoUri=https://graph.facebook.com/v13.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture.width(250).height(250)
For google, this is working well - the application has an authorization rest controller which redirects to the google auth end point. After logging in, I can see a code is returned and sent to a redirect URI {baseUrl}/ouath2/callback/google, which is exchanged for a token which is in turn parsed and used to construct a universal application-level Oauth2 bearer token (for use in my shared APIs etc).
For facebook, I am attempting a similar setup. The initial redirect works, and user is directed to a facebook login page with equivalent client_id / redirect uri parameters set:
https://www.facebook.com/v3.0/dialog/oauth
?response_type=code
&client_id=<fbClientId>
&scope=email+public_profile
&state=<state>
&redirect_uri=https%3A%2F%2F192.168.50.150.nip.io%3A8300%2Foauth2%2Fcallback%2Ffacebook
&ret=login
&fbapp_pres=0
&logger_id=e1036c5a-ac6e-448c-ab8g-655727eae993
&tp=unspecified
&cbt=1643459835928
&ext=1645463198
&hash=AeJog6HeUz9jlsDRQQo
However, when the code is obtained after login and sent to the redirect uri {baseUrl}/ouath2/callback/facebook, there is an error returned when my application attempts to access the FB User Info resource server:
I don't have any traffic capture from my backend to the FB User Info URI, so I can't see exactly what's being sent, but the response I get back is a server error:
[invalid_user_info_response] An error occurred while attempting to
retrieve the UserInfo Resource: Error details: [UserInfo Uri:
https://graph.facebook.com/v3.0/me?fields=id,first_name,middle_name,last_name,name,email,verified,is_verified,picture.width(250).height(250),
Error Code: server_error]
Are there any known issues with the graph.facebook.com end points?

openiddict - The specified authorization code is invalid

I have written a web API in .NET core 2.0 and using openiddict. When testing the external login use case, the following steps are followed.
User calls into account controller specifying their external login provider which starts the Challenge process.
/api/account/externallogin?provider=Facebook
The result of the Challenge process calls back to API (ExternalLoginCallback) with successful result and redirects to the following API endpoint to return an authorization code to the client via the redirect_uri.
/connect/authorize?client_id=myClient&response_type=code&scope=offline_access&redirect_uri=http://myClient/signin-oidc";
The client receives the code via the redirect_uri with code appended as shown below
http://myClient/signin-oidc?code=CfDJ8Agzs3e68m5Ev0zC5okWI7--_T13E-ULHqeUlzgmEWBcPj6PYBBzAWu0kssa0wl3OcYX-YG0jCzhLZr2Wajvjc_zJTsmK12rmRjPAzqbqu9OuMjDX-wzNQYMI0cpLW1ZuumvPZHiRP5hxWAVpgH1pu5VwdcQBTBpyOPOP0JD2Wba1VAF9iopN1YIquLkvtVXnJEEKhb1apqfJAkA_NNk2lSRxFBkq6rFn9wLEOt2y9b0fOqsJ0sqmA1jbhJVfiVPaaI8z3J8HnzFtMwNHTwgpU8gAjk9ZTeTuP86nxQZl8R-P7LgEvOs8AgTR1g_WBSZgwtPfpULV3Ib7iUn8BQ4PiDhcwVR3Wed9Utnmbx5w8iDV9-jo4QRleuH8QWmZxXqr2nyeeCKqC01VHoEGl1KJak1jcxzFg7ooZAM_yrD207n0jy-hX9dvyl6XezSND5-ltjWjM1b96iK_74X8Euf4YVlhcV2bWPzBmgBSWQydOfT_xv3HNmXQcWwXjlEcCaxzdAKTconRDUuycBsdLS1Je6cME5deT9fzp98Lt6ryuVGNtkkqGg0LcKv49JmPyiBHrQfQUOUQg8fXkCYrf7k8FG5N8e-k3X1P3NEcYFcMchxF_1s1T2lUGAfmJ3P8Yqd9j26PF-gWzQHwkcdz1ptwbIXmF-tHuQK8zmIHoa5ErB3lR5bffsZmmG77NpTT-yq82Bbl5yf32RXKunqf5rQrVF7cWX0eM1h-EDgeHiMwx2IOYkHcxK6JLcRlggDfG__wMn_vEsQwW5UJaKU1VywT3hBGvS-zmbseparILu8hGDL5DrpmLpE3a5obWsp1yCM33fb7ciYmWuwQXKldG7MWXg#=
Client immediately extracts the code from the URL and posts to the following endpoint to receive access/refresh tokens, but receives an error of invalid grant with error description of The specified authorization code is invalid.
/connect/token
The following values are submitted in the post to request access token:
grant_type = authorization_code
code =
CfDJ8Agzs3e68m5Ev0zC5okWI7--_T13E-ULHqeUlzgmEWBcPj6PYBBzAWu0kssa0wl3OcYX-YG0jCzhLZr2Wajvjc_zJTsmK12rmRjPAzqbqu9OuMjDX-wzNQYMI0cpLW1ZuumvPZHiRP5hxWAVpgH1pu5VwdcQBTBpyOPOP0JD2Wba1VAF9iopN1YIquLkvtVXnJEEKhb1apqfJAkA_NNk2lSRxFBkq6rFn9wLEOt2y9b0fOqsJ0sqmA1jbhJVfiVPaaI8z3J8HnzFtMwNHTwgpU8gAjk9ZTeTuP86nxQZl8R-P7LgEvOs8AgTR1g_WBSZgwtPfpULV3Ib7iUn8BQ4PiDhcwVR3Wed9Utnmbx5w8iDV9-jo4QRleuH8QWmZxXqr2nyeeCKqC01VHoEGl1KJak1jcxzFg7ooZAM_yrD207n0jy-hX9dvyl6XezSND5-ltjWjM1b96iK_74X8Euf4YVlhcV2bWPzBmgBSWQydOfT_xv3HNmXQcWwXjlEcCaxzdAKTconRDUuycBsdLS1Je6cME5deT9fzp98Lt6ryuVGNtkkqGg0LcKv49JmPyiBHrQfQUOUQg8fXkCYrf7k8FG5N8e-k3X1P3NEcYFcMchxF_1s1T2lUGAfmJ3P8Yqd9j26PF-gWzQHwkcdz1ptwbIXmF-tHuQK8zmIHoa5ErB3lR5bffsZmmG77NpTT-yq82Bbl5yf32RXKunqf5rQrVF7cWX0eM1h-EDgeHiMwx2IOYkHcxK6JLcRlggDfG__wMn_vEsQwW5UJaKU1VywT3hBGvS-zmbseparILu8hGDL5DrpmLpE3a5obWsp1yCM33fb7ciYmWuwQXKldG7MWXg#=
redirect_uri = http://myClient/signin-oidc"
cient_id = myClient
client_secret = mySecret
scope = offline_access role email openid

Google Oauth Error: redirect_uri_mismatch

I'm trying to use google Oauth 2 to authenticate with google calendar API for a web server running on AWS EC2.
When I generated the credentials I selected 'OAuth Client ID' and then 'Web Application'. For the Authorised redirect URIs I have entered:
http://ec2-XX-XX-XX-XXX.eu-west-1.compute.amazonaws.com
(I've blanked out the IP of my EC2 instance). I have checked this is the correct URL that I want the callback to go to.
The link that is generated in the server logs is of the form:
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=XXXXXXXXXXXX-XXXXXXXXXXXXXX.apps.googleusercontent.com&redirect_uri=http://localhost:47258/Callback&response_type=code&scope=https://www.googleapis.com/auth/calendar.readonly
When I follow the link I get the error
'Error: redirect_uri_mismatch'.
I've read this SO question and have checked that I am using HTTP and there is no trialing '/'
I suspect that the URL generated should not have 'localhost' in it but I've reset the client_secret.json several times and each time I restart tomcat with the new client secret I still get a link with localhost but just over a different port.
Locally, I had selected Credentials type of 'other' previously and was not given an option for the Authorised redirect URI. I did try this for the EC2 instance but this won't give me the control I want over the redirect URI and sends the redirect over localhost.
Google throws redirect_uri_mismatch when the uri (including ports) supplied with the request doesn't match the one registered with the application.
Make sure you registered the Authorised redirect URIs and Authorised JavaScript origins on the web console correctly.
This is a sample configuration that works for me.
In case you are seeing this error while making API call from your server to get tokens.
Short Answer 👇 - What solved my problem
use string postmessage in place of actual redirectUri that you configured on cloud console.
Here is my initilization of OAuth2 client that worked for me.
// import {Auth, google} from 'googleapis`;
const clientID = process.env.GOOGLE_OAUTH_CLIENT_ID;
const clientSecret = process.env.GOOGLE_OAUTH_CLIENT_SECRET;
oauthClient = new google.auth.OAuth2(clientID,clientSecret,'postmessage');
My Case
On the frontend, I am using react to prompt the user for login with google with the authentication-code flow. On success, this returns code in the payload that needs to be posted to the google API server to get token - Access Token, Refresh Token, ID Token etc.
I am using googleapis package on my server. Here is how I am retrieving user info from google
// import {Auth, google} from 'googleapis`;
const clientID = process.env.GOOGLE_OAUTH_CLIENT_ID;
const clientSecret = process.env.GOOGLE_OAUTH_CLIENT_SECRET;
oauthClient = new google.auth.OAuth2(clientID,clientSecret,'postmessage');
/*
get tokens from google to make api calls on behalf of user.
#param: code -> code posted to backend from the frontend after the user successfully grant access from consent screen
*/
const handleGoogleAuth = (code: string) => {
oauthClient.getToken(code, async (err, tokens: Auth.Credentials) {
if (err) throw new Error()
// get user information
const tokenInfo = await oauthClient.verifyIdToken({
idToken: tokens.id_token
});
const {email, given_name, family_name, email} = tokenInfo.getPayload();
// do whatever you want to do with user informaton
}
}
When creating a Oath client ID, DO NOT select web application, Select "Other". This way, the Redirect URI is not required.

How to exchange Google one-time authorization code for a refresh token without callback (intranet)?

I'm working on a intranet-based application and I want to use Google services. Currently I have successfully implemented Google Authentication with "Sign-In for Websites" using JavaScript client-side authentication. My users can now sign in or sign up with their Google accounts.
Now I want to use Google API to create and share Google Sheets with my users. These documents will be created with a specific Google account and then shared with my users.
This is why I want to use this server-slide flow to get a one-time authorization code and exchange it for a refresh token:
https://developers.google.com/identity/sign-in/web/server-side-flow
This refresh token will be stored in my database allowing me to user Google services on behalf of this offline user.
Using JavaScript library, I was able to get the one-time authorization code that I send to my server with a AJAX request.
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(grantOfflineAccessCallback);
var grantOfflineAccessCallback = function(authResult) {
var auth_code = authResult.code;
// Exchange the one-time authorization code for tokens
$.post(...);
}
On server-side I use Google API PHP Client (v2.0.0-RC6) to acquire an access and refresh token.
$this->client = new Google_Client();
$this->client->setClientId($this->clientId);
$this->client->setClientSecret($this->clientSecret);
$this->client->setAccessType('offline');
$this->client->setApprovalPrompt('force');
$response = $this->client->fetchAccessTokenWithAuthCode($oneTimeCode);
I wasn't able to exchange the authorization code.
Client error: `POST https://www.googleapis.com/oauth2/v4/token` resulted in a `400 Bad Request` response:
{
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
On this page we can read:
On the server, exchange the auth code for access and refresh tokens.
Use the access token to call Google APIs on behalf of the user.
On the JAVA example code:
REDIRECT_URI: // Specify the same redirect URI that you use with your web
// app. If you don't have a web version of your app, you can
// specify an empty string.
Because the application I working on is an intranet application, I tried to specify an empty string for this redirect_uri parameter before calling fetchAccessTokenWithAuthCode() method:
$this->client->setRedirectUri('');
... result in Redirect URI must be absolute.
Can we use this hybrid server-slide flow without callback URL?
Is there any solution to my problem?
Thanks,
Edit:
redirect_uri is where the user will be redirected to after he signed in. This URL must be registered in the Google Project (developers console). So redirect_uri is NOT the callback...!
Problem is now solved with:
$this->client->setRedirectUri('http://same.url.as.in.developers.console/');

Resources