CORS Error in a working setup while trying to authenticate using Google+ API in React/Node setup - node.js

I was implementing the Oauth2.0 authentication using Google. I used react-google-login npm on the frontend to authenticate the user using Google Oauth2.0. I successfully created the CLient-id and secret under google cloud platform for my project, along with the URI as needed.
The frontend is running on default localhost:3000 and backend (node/express) running on localhost:9001 with proxy enabled on frontend to redirect the request to backend.
I was able to authenticate using Google more than 2 dozen times last night as i was working on the backend siginIn contoller. I was also able to add the user to my Mongodb after successful authentication from Google.
All of a sudden, i was getting CORS error which is a bit strange as none of the code or Google configs were changed.
My Google config looks as follows.
My code on the frontend is still successfully redirecting the user to Google for authentication. Its also generating the right google credentials.
SignIn Component Code snippet passing the info to responseGoogle which resides in withLogin HOC Parent Component.
<GoogleLogin
clientId={GOOGLE_CLIENT_ID}
buttonText="Google"
render={(renderProps) => (
<button onClick={renderProps.onClick} style={customStyle}>
<img className="googleBtn" src={googleIcon} alt="GMAIL ICON" />
</button>
)}
onSuccess={responseGoogle}
onFailure={responseGoogle}
cookiePolicy={"single_host_origin"}
/>
withLogin HOC Parent Component dispatching the info to Redux thunk.
const responseGoogle = (res) => setGoogleResp(res);
useEffect(() => {
googleResp?.error &&
setValues({ ...values, serverError: "GOOGLE LOGIN FAILED" });
googleResp?.tokenId && dispatchGoogleSignInDataToBackend()
}, [googleResp]);
const dispatchGoogleSignInDataToBackend=async ()=>{
const data=await dispatch(allActions.googleSignInAction(googleResp,whoLoggedIn));
if (data.error) {
setValues({ ...values, serverError: data.error, success: false });
} else {
const {
email,
name,
_id,
role,
listOfEmailOfAllClientsForLawyerLogin,
} = data.userCred;
saveJwtToLocalStorage(
data.token,
{ name, email, _id, role, listOfEmailOfAllClientsForLawyerLogin },
() => {
setValues({
email,
serverError: false,
success: true,
});
}
);
}
}
I am sending the appropriate CORS header in the request to the backend.
export const dataHeaders = {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json",
"Access-Control-Allow-Headers" :"*"
};
Redux thunk code:-
export const googleSignInAction=(googleResp,whoLoggedIn)=>{
console.log("Login Success: currentUser:", googleResp);
return async (dispatch) => {
dispatch({ type: SIGNIN_LOADING });
try {
const response = await axios.post(
`${API_URL}/googlesignin`,
{
googleResp,
whoLoggedIn
},
{
headers: dataHeaders,
}
);
console.log("response inside googleSignInAction", response);
// CHANGED COZ OF ESLINT WARNING.
if (
response.status === 201 &&
Object.keys(response.data).includes("token") &&
Object.keys(response.data).includes("userCred")
) {
dispatch({ type: SIGNIN_SUCCESS, data: response.data });
return response.data;
} else {
dispatch({ type: SIGNIN_FAILED });
}
} catch (error) {
dispatch({ type: SIGNIN_FAILED });
return error.response.data;
}
};
}
API URL Points to following:-
export const API_URL="http://localhost:9001/api";
No request is reaching the backend because of CORS error.
Frontend receiving the Correct Response from Google Post authentication.
Errors on the Frontend.

Browsers will first send a pre-flight request to check CORS. In your backend code, you have to allow the front-end host and port. In this case localhost:3000.
The reason you are getting the cors error is bacause its on two different ports.
But if proper cors response is given by backend (port 9000), it will resolve.

Clearing the browser cookies and cache made everything work again. googlesignin is working without cors error. I have added following line of code to serve all static files from backend to frontend.
app.use(express.static(path.join(__dirname, '../frontend/public')));

Related

Reactjs + Express Twitter API "Could not authenticate you."

I am trying to create a very simple app that allows me to post a tweet. I am currently using React running on port 3000 and express server.js running on port 5000
my server.js has the following:
app.post("/twitter/message", async(req, res) => {
const tweet = req.body.tweet;
try {
const response = await postToTwitter(tweet);
res.json({
message: 'Tweet successfully posted to twitter'
});
} catch (error) {
res.status(500).json({
message: 'Not able to post'
});
}
});
function postToTwitter(tweet) {
client.post(
"statuses/update",
{ status: tweet },
function (error, tweet, response) {
if (error) log(error);
/* log(tweet); // Tweet body. */
}
);
}
I am then using a script on the index.html page to post the input tweet:
<script>
$('button').on('click', (event) => {
event.preventDefault();
const tweet = $('#tweet').val();
// Post Tweet
$.ajax({
url: '/twitter/message',
method: 'POST',
data: {
tweet
}
})
.then(() => {
alert('Data successfully posted');
console.log('Data successfully posted');
})
.catch((error) => {
alert('Error: ', error);
console.log('Error: ', error);
});
})
</script>
This however is giving me the bellow error when I hit the post button:
[ { code: 32, message: 'Could not authenticate you.' } ]
If I use this exact same setup with just express it works perfectly fine, the issue occurs when trying to use react. Any help would be amazing.
It is possibly a CORS issue (which would show up in the frontend but not in Node/Backend).
If you're using some sort of API key to make the API request you're not showing it in this sample (don't show people your API key). By similar logic, do not have your API key on the client side, as anyone downloading your website would then have your Twitter API key. Instead, for multiple reasons it is better to have the backend be the one to make the API requests with your API key.
On the other hand if users are supposed to authenticate via O-Auth and you're supposed to pass a cookie with your authentication make sure you useCredentials on the request. axios.post(BASE_URL + '/api', { withCredentials: true }); . Looks like you're using jquery so add the same withCredentials:
Try adding this to your options:
crossDomain: true,
xhrFields: {
withCredentials: true
},
If you don't see a cookie when you type document.cookie in the browser that's probably a sign you're not authenticated in your computer.

Node js login using passport-local working in postman but getting error in frontend Vue JS

I am using passport-local for user authentication. When I try to get logged in User it works in postman but gives error message which i set to "You need to be logged in first to get data". My user is successfully logging in from vue js but when i try to get logged in user its gives my error message.
here is my route :
router.get('/jobs', auth ,async(req, res) => {
const jobs = await Job.find({}).sort({
createdAt : -1
})
console.log(req.user)//This is working in postman but gives error in vue js
res.send(jobs)
})
I am using cors and specifying origin and set credentials to true.
here is my frontend request :
try{
const res = await axios.get('http://localhost:3000/jobs', {
withCredentials : true
})
this.jobs = await res.data
console.log(this.jobs) // It gives my error message even i am logged in
}catch(error) {
if(error.response) {
this.message = error.response.data
}
}
If you use token, you need to pass it with your request like that:
const config = {
withCredentials : true,
headers: {
Token: user.value.token
},
};
try{
const res = await axios.get('http://localhost:3000/jobs', config)
this.jobs = await res.data
console.log(this.jobs) // It gives my error message even i am logged in
}catch(error) {
if(error.response) {
this.message = error.response.data
}
}
Look in postman the headers you are sending.
edit: added image

Handle login using Google Authentication in system with client and server running on different port reactJS and nodeJS

Currently I'm working in proj using different port at client and server. I'm confusing about handling event in Client whenever login successful in Server. I don't know how to process to login at Client too. I'm using PassPortJS.
I added a button to handle onClick event in client, than start calling server to Authentication with Google by:
let gg_window = window.open("http://localhost:7000/authentication/google/auth", "_self");
I also config my google app for Authentication as below (Client running on port 9000, server in port 7000)
Google Authentication configuration
In Server:
I made an endpoint to handle URL as:
router.get('/google/auth',
passport.authenticate('google', {
scope:
'https://www.googleapis.com/auth/plus.me https://www.google.com/m8/feeds https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile'
})
);
router.get('/google/auth/redirect',
passport.authenticate('google'),
(req, res) => {
const token = jwt.sign(JSON.stringify(req.user), SECRET);
res.redirect("http://localhost:9000/google/auth/success?username=" + req.user.username + "&token=" + token);
});
I can get token, username... and redirect to client is ok
In Client
I'm using Redux-Saga, normal login with username and password is implemented before.
What should I do now? Thanks for any helping.
I'd implemented this feature by this way:
In Client:
Made an component to handle end-point "/google/auth/success" as:
<Route
component={ConfirmAccount}
path="/google/auth/success"
/>
In ConfirmAccountView, I've made a view to confirm UserName which inputted by user. Then have a button to confirm Account.
I made useEffect() of Hook to handle this View and save data to localStorage like:
useEffect(() => {
if (isLoggedIn === true) {
localStorage.setItem("authorize_token", authorization_token)
localStorage.setItem("user", username)
history.push('/profile')
}
if (error) {
NotificationManager.error(`${error}`, "Login Failed")
}
if (localStorage.getItem("authorize_token")) {
history.push('/profile')
}
}, [isLoggedIn, error]);
I also made a connect function to get state and post action to reducer:
const mapStateToProps = createStructuredSelector({
isLoggedIn: isLoggedIn(),
authorization: authorization(),
error: displayError()
});
const mapDispatchToProps = dispatch => {
return {
loginSuccessWithGG: username => {
dispatch(loginSuccessWithGG(username)); // Action dispatch for signin
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(ConfirmAccount);
In Redux-Saga, I made an action to dispatch action SignInSuccessful to reducer, then Reducer will set state isLoggedIn to True.
It's worked now.

Express response methods don't work after verifying ID token from Firebase through a middleware

I am trying to build a web application using Firebase and NodeJS with ejs templates at the client. I want to make sure the user is authenticated before accessing a particular route through a middleware. In this middleware, I verify ID tokens sent through the client and then render the page if they are verified. But when the tokens are verified the app doesn't show the new page i.e. "user-profile.ejs".
<button onclick="sendRequest('/profile')">Profile</button>
//The client function which sends ID token
function sendRequest(url){
if(firebase.auth().currentUser){
firebase.auth().currentUser.getIdToken(true)
.then(idToken => {
client({
method: 'get',
url: url,
headers: {
'authtoken': idToken
}
})
.then(res => {
console.log("Auth token sent.")
})
.catch(err => {
console.log(err)
})
})
.catch(err => {
console.log(err)
})
}else{
client({
method: 'get',
url: url,
}).then(res => {
console.log("Request sent without header.")
})
.catch(err => {
console.log(err)
})
}
}
//The NodeJS server which contains the routes and checkAuth middleware
function checkAuth(req,res,next){
if(req.headers.authtoken){
console.log('Auth token with headers received. User has logged in.')
admin.auth().verifyIdToken(req.headers.authtoken)
.then(verifiedUser => {
console.log('Auth token verified')
return next()
})
.catch(err => {
console.log(err)
res.redirect('back')
})
}else{
console.log('Without header received.')
res.redirect('back')
}
}
app.get('/',(req,res)=>{
res.render('home')
})
app.get('/profile',checkAuth,(req,res)=>{
console.log("Reached user profile")
res.send("user-profile")
})
Remember that when you redirect, the client get the redirected URL and issues an entirely new http request. That starts a completely new request cycle on your server that will go through all your middleware again that matches that new URL.
Automatic client redirects do NOT include custom headers from the original response. If that's what you were expecting, that will not work. If you're following a redirect manually from an Ajax call, you can manually get the token from the redirect response header and manually add it to a new Ajax call to the redirected location.
If you're expecting the browser or some automatic redirect to handle the redirect, they won't take the token with them from the headers. So, your server will have to either send the response to the original URL without redirecting or you will have to put the token in something that will survive the redirect such as a query parameter on the redirect (usually a bad idea for a credential) or in a cookie or in a server-side session object that is tied to a cookie.

How to Authenticate the logged in user from a MERN application inside React-Redux And Check with every request?

I am working on my second React/Redux application (I'm new to Redux) and also the first MERN stack app altogether.
Currently, I am having an Authentication problem on the Front-End side in React/Redux Which goes like this:
I have established a protect middleware in my Back-End to check if the user which logged in is always logged in with valid JWT-Token or not by setting the Token inside the Browser Cookie with HttpOnly flag enabled {no secure flag yet but I will enable that too in production step}
The main problem is that once I log in the application, everything is fine and if the user is validated without any errors then inside the authReducer, the isAuthenticated property will be set to true and then logged in user's data is passed to the redux store to be used. but once I redirect to the main feed page of the app everything is gone the isAuthenticated is now false and user data is null so the app crashes.
I know that I must call the auth protected route every time I send a request to the server but I am stuck because it needs some piece of the logged-in user like username or ID to be sent along with the each request to validate it and I can't store them in local storage because of safety issues. { storing sensitive data in local storage is not a good practice}
this is log in function in Redux Actions:
export const loginUser = (loginData) => async (dispatch) => {
try{
setLoading();
const res = await axios({
method: "post",
url: "/users/login",
data: {loginData}
});
dispatch({
type: TYPES.LOGIN_SUCCESS,
payload: {
status: res.data.status,
token: res.data.token,
user: res.data.data.user
}
});
// This below code will set the logged in user after successful login
getLoggedInUser(res.data.data.user.username);
}catch(error){
dispatch({
type: TYPES.LOGIN_FAIL,
payload: {
status: error.response.data.status,
message: error.response.data.message
}
});
}
};
as you see after the successful log in, the token and user data is dispatched to store but after component reload they are gone so I can't re-Authenticate the logged in user.
this is my getLoggedInUser redux action function:
export const getLoggedInUser = (userName) => async (dispatch) => {
try{
setLoading();
const res = await axios.get(`/auth/${userName}`, {
// headers:{
// Cookies: `jwt=${token}`
// }
});
dispatch({
type: TYPES.GET_LOGGED_IN_USER,
payload: res.data.data.loggedInUser
});
}catch(error){
dispatch({
type: TYPES.AUTH_ERROR,
payload: {
status: error.response.data.status,
message: error.response.data.message
}
});
}
};
Any solutions?

Resources