Google Oauth2 giving "redirect_uri_mismatch" error in production when redirect uri setup correctly - reactjs

I have google oauth set up in a react project. It was working fine in development, locally. Once i promoted the oauth client to "production" and modified the JS origin and redirect URIs to production values, yet it gives this error
Error 400: redirect_uri_mismatch
You can't sign in to this app because it doesn't comply with Google's
OAuth 2.0 policy.
If you're the app developer, register the redirect URI in the Google
Cloud Console. Request details:
redirect_uri=http://super-server.herokuapp.com/v1/auth/google/callback
Related developer documentation
These are the authorized redirect URIs within google cloud console:
https://super-server.herokuapp.com/v1/auth/google/callback
https://super-server.herokuapp.com/v1/auth/google/callback/
https://www.super-server.herokuapp.com/v1/auth/google/callback
https://www.super-server.herokuapp.com/v1/auth/google/callback/
As you can see, there are no authorized uri's with an HTTP schema. Theyre not even allowed in production mode. So im not sure where this is coming from, because the server is HTTPS
server:
Any advice?

the redirect uri must exactly match the one you are adding to Google developer console
If you check the error message your app is running with
http://super-server.herokuapp.com/v1/auth/google/callback
All the ones you have added are https
May i suggest fixing your app so that it runs https. I dont think that you will be able to add http as a production redirect uri endpoint.
documentation
Obtaining OAuth 2.0 access tokens
authorization-errors-redirect-uri-mismatch
Node.js
I dont know enough about react.js but with node you should be able to do something like this
const http = require('http');
const https = require('https');

In my case (MERN + passport.js), i had a configuration that looked like:
const googleOptions = {
clientID: config.google.id,
clientSecret: config.google.secret,
passReqToCallback: true,
callbackURL: '/v1/auth/google/callback',
scope: ['profile', 'email']
};
Even though the server, the client && the configuration of the oauth client within google api console were all in production with everything setup for https, for some reason, the callbackURL kept firing with google oauth as http://my-domain.com/v1/auth/google/callback
so this fix may be hacky, but it did fix my oauth issues:
//Google Strategy
const googleOptions = {
clientID: config.google.id,
clientSecret: config.google.secret,
passReqToCallback: true,
callbackURL: config.environment == 'production' ? 'https://super-server.herokuapp.com/v1/auth/google/callback' : '/v1/auth/google/callback',
scope: ['profile', 'email']
};

Looks like the redirect_uri on the client side (React side) is set to http://super-server.herokuapp.com/v1/auth/google/callback
Change the redirect_uri on the client side from (http) http://super-server.herokuapp.com/v1/auth/google/callback to (https) https://super-server.herokuapp.com/v1/auth/google/callback.

Related

CORS policy is allowed in app.py but still not working

The front-end app is built on ReactJs and development server is running on http://localhost:3000. The back-end API is built with Flask 2.0.2 and is running on http://localhost:5000
In app.py file, the CORS has been allowed as mentioned in the documentation like:
CORS(app, resources={r"*": {"origins": "*"}})
When I try to submit the login form I still get the following error:
if you Enables CORS on your backend api , it should work.
I don't think this is an issue with your react frontend application.
cors is a security measure put in by browsers.
You could bypass the Cross-Origin-Policy with chrome extension but it's not advisable -
Try this on your backend API:
Ensure you have flask cors installed
create a configuration dictionary like this
api_v1_cors_config = {
"origins": ["http://localhost:5000"]
}
You can then set a global cors for your app like this
CORS(app, resources={"/api/v1/*": api_v1_cors_config})
// this would allow all methods, origins

OAuth responses require a User Pool defined in config

I am unable to connect to userpool which I defined right above: Auth is an amplify Object
Auth.configure({
region: process.env.REACT_APP_AWS_REGION,
userPoolId: process.env.REACT_APP_PROD_UNIFY_COGNITO_USER_POOL_ID,
userPoolWebClientId: process.env.REACT_APP_PROD_UNIFY_COGNITO_CLIENT_ID,
// Cognito Hosted UI configuration
oauth: {
domain: process.env.REACT_APP_PROD_UNIFY_COGNITO_DOMAIN,
scope: ['email', 'openid', 'aws.cognito.signin.user.admin', 'profile'],
redirectSignIn: 'http://localhost:3000',
redirectSignOut: 'http://localhost:3000',
responseType: 'code',
},
});
I get this error in my browser :Unhandled Rejection (Error): OAuth responses require a User Pool defined in config
AuthClass.
What else is there to connecting programmatically to a user pool. I didn't do amplify push,add auth or anything with the amplify cli b/c I don't think it's necessary?
This is most often down to the fact that you have changed your .env file, but not stopped and restarted your local web server.
For instance if you use yarn serve, make sure you stop the process, then update your .env, then yarn serve again.

https associated to an insecure XMLHttpRequest endpoint

My website is hosted on a cloud run app : https://ap4-xxxxxxxx.a.run.app/.
This website is calling an API which is hosted here https://ap4-xxxxxxxx.a.run.app/api/undefined. But this request is blocked in my browser .
Error message :
Mixed Content: The page at 'https://ap4-xxxxxxxx.a.run.app/' was
loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint
'http://ap4-xxxxxxxx.a.run.app/api/undefined/'. This request has been
blocked; the content must be served over HTTPS.
The API https://ap4-xxxxxxxx.a.run.app/api/undefined is working perfectly on my browser or with postman. And the code requesting it explicitly mentionned https :
const request = https://ap4-xxxxxxxx.a.run.app/api/${variable};
axios.get(request)
.then(result => {
const PlaceList = result.data.map(
station => {
const isFavorite = PlaceId.includes(Place.number);
return { ...Place, isFavorite: isFavorite }
}
);
this.setState({
PlaceList: PlaceList,
isLoading: false
})
updateFavPlaceList(PlaceList);
})
I don't understand what's wrong here. Is my app making an http call instead of https ? I read here (Page loaded over HTTPS but requested an insecure XMLHttpRequest endpoint) that, some https are self signed. Is it the case of cloud run?
I've tried Cors, but it did not help.
Any observation or suggestion would be very much appreciated.
It seems you are indeed somewhere making an HTTP:// request in your frontend or make sure your app doesn't issue redirects to http://.
.app domains are in hardcoded HSTS list of your browser. If you type any .app domain, it will be requested as https:// .There's no way to access a .app domain over http:// in a modern browser, even with XHR.
So here is a quick fix. I forced my backend (flask) to generate https url.
Using the answer from here : Flask url_for generating http URL instead of https
class ReverseProxied(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
scheme = environ.get('HTTP_X_FORWARDED_PROTO')
environ['wsgi.url_scheme'] = 'https'
app = Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)
There might be a better way (maybe forcing the frontend to request https), so feel free to comment on this.

React App + Spring Boot - JWT auth token inside a cookie is not set in Chrome

I'm trying to configure Spring Boot to set-cookie containing JWT auth token following a sign-in request from my react app, and then the expectation is that the browser will automatically set this cookie to all requests as specified by the cookie path. The behaviour is ok on my friend's environment - same code, Chrome browser, different machine. I tried clearing node_modules, mvn clean install, also tried different browsers Chrome and FireFox, no success.
Here is the all the relevant code (let me know if I'm missing something else important)
React is running on localhost:3000
Spring Boot is running on localhost:8080
There is a proxy in the package.json
"proxy": "http://localhost:8080",
To test the auth flow we are issuing a sign-in request from the sign-in form (react), the request is successfully proxied to port 8080 and the response from the server is successfully returning the JWT token as part of an auth cookie. The cookie is specified to the /api path. Network request as seen in Chrome below:
Immediately after the login, the react app is issuing a second HTTP request to the back-end, but a break-point on the server shows no cookies are passed from the browser as part of this request. The request is to http://localhost:3000/api/user.
In the front-end we are using fetch to make that request and it looks like this:
fetch("/api/user, {
credentials: "same-origin"
})
Just for additional context this is how we return the original cookie from the server, upon a successful login:
#PostMapping("/signin")
public ResponseEntity signin(#RequestBody AuthenticationRequest data, HttpServletResponse response) {
try {
String username = data.getUsername();
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, data.getPassword()));
User user = (User) authentication.getPrincipal();
String token = jwtTokenProvider.createToken(user);
final Cookie cookie = new Cookie("auth", token);
cookie.setSecure(!environment.acceptsProfiles(Profiles.of("dev")));
cookie.setHttpOnly(true);
cookie.setMaxAge(Integer.MAX_VALUE);
cookie.setPath("/api");
response.addCookie(cookie);
return ok(buildUserResponseObject(user));
} catch (AuthenticationException e) {
throw new BadCredentialsException("Invalid username/password supplied");
}
}
Is there anything wrong with our approach? What could be preventing my browser from passing on the auth cookie?
Oh this is embarrassing...
The issue was this line
cookie.setSecure(!environment.acceptsProfiles(Profiles.of("dev")));
!environment.acceptsProfiles(Profiles.of("dev")) was evaluating to true and it was causing the cookie to be only passed if the connection is secure, which it wasn't because it was localhost. Mystery solved.

Access-Control-Allow-Origin Error Only on a Single Route, Only When Deployed to GAE

I'm using google app engine to host both my frontend and my api backend. I'm getting the following errors when I'm polling the "slicingdone" route on my backend:
bootstrap e65cef5bb029055e1719:2 GET
https://playloopsbackend-217106.appspot.com/playloops/slicingdone 502
send # bootstrap e65cef5bb029055e1719:2
/videotogifs:1 Access to XMLHttpRequest at
'https://playloopsbackend-217106.appspot.com/playloops/slicingdone'
from origin 'https://playloopsfrontend.appspot.com' has been blocked
by CORS policy: No 'Access-Control-Allow-Origin' header is present on
the requested resource.
I poll the slicingdone function to figure out when trimming of a video on my backend is finished. It works locally but is presenting the above errors when deployed to gcloud.
slicingdone function on my backend looks like this(Express):
slicingdone(req, res, next) {
if(slicingIsDone == true){
res.status(200).send('true');
slicingIsDone = false;
}else{
res.status(200).send('false');
}
}
*Every other route on my backend works fine even when deployed. I have similar functions on the backend that manipulate videos using ffmpeg in different ways. I have whitelisted my frontend url on my backend, so I'm not sure why I'm getting these CORs errors. I store the video results in google cloud storage--perhaps I need to add my backend url to google cloud CORS whitelist?
Any help is much appreciated! Thank you!

Resources