No 'Access-Control-Allow-Origin' header is present on the requested resource. - React/Node API - node.js

I'm trying to get passport authentication with twitter to work. My setup is as follows: React(with redux) frontend (create-react-app), Node (with express) API. Both are running on localhost (different ports).
User goes to /login and clicks on a button that dispatches a login action:
export function login() {
return dispatch => {
return axios.get('/api/auth/twitter')
.then(() => {})
}
}
The route on the server:
router.get('/twitter', passport.authenticate('twitter'));
And the route for the callback:
router.get('/twitter/callback', passport.authenticate('twitter', {failureRedirect: '/login'}), loginSuccess);
loginSuccess does nothing at the moment.
This is the full error I get:
XMLHttpRequest cannot load https://api.twitter.com/oauth/authenticate?oauth_token=fGVctgAAAAAA1y22AAABXah3t3o. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:3000' is therefore not allowed access.
I'm proxying requests from the react frontend (localhost:3000) to localhost:8080.
If I go into the network tab of the chrome devtools and select the response from the twitter api it looks like this:
If anyone knows how to get passport-twitter authentication to work with this kind of setup please let me know.

Sad news, Twitter won't let you to call its API client-side, you need a server in order to do that :(
Take a look at this Quora answer.

Related

React + Express With Passport.js

I am setting up a full-stack application using React and Express JS.
I'm using Passport.js for authentication and have come across a slight problem...
So my front-end and back-end are two separate packages running on two different ports. On my express app, I have created a route like the following.
app.post('/api/account/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
}) (req, res, next);
});
This is pretty standard as far as Passport.js goes. Basically, if it authenticates the credentials I have provided, then it should redirect me to /dashboard. If not, then to the other mentioned route.
I am able to call reach this endpoint from my react application and get the correct response like the following in the network tab of chrome.
Request URL: http://localhost:3000/dashboard
Request Method: GET
Status Code: 304 Not Modified
Remote Address: 127.0.0.1:3000
Referrer Policy: no-referrer-when-downgrade
However, it doesn't actually redirect me to /dashboard. Is it not possible to do it this way?
Thanks.
It sounds like your React app is calling the route via ajax using something like fetch.
The way you're using Passport assumes that a browser is issuing the requests directly. On a successful login, Passport returns a Redirect response (HTTP 302 or similar), which the browser honors and redirects the user to.
Ajax requests don't work this way, since there isn't any navigation happening.
You'll need to handle this yourself on the React side of things. Your Express app will need to handle the session authentication by (for instance) returning a JSON message with a token or storing a session cookie. You'll need to update your React app to recognize this and then navigate to the correct route via client-side Javascript.
If you're using react-router, they have some sample code that might be helpful.

How can I redirect a page from an external Node/Express server

I have a React/Node/Express web app up and running with two separate servers. React is running on localhost:8080 and proxying API requests to my node server running on localhost:3000. This will be my setup for production, so if possible, I would like to leave this structure intact.
The problem I'm running into is part of my API needs to redirect the user to a page to grab a token from the Spotify API, and then redirect back to my correct page upon successful authentication.
The API call proxy is being done like this:
const axios = require('axios');
const axiosInstance = axios.create({
baseURL: process.env.NODE === 'production' ? '' : 'http://localhost:3000'
});
module.exports = axiosInstance;
Up to this point, this works great, as I can keep my React and Node server completely separate.
As I mentioned above, I need to redirect my React front-end through an API call on my back-end, to a different page (Spotify authentication) to authenticate users, which then Spotify redirects back to my site after a user allows or disallows access to their Spotify accounts.
On my front-end - localhost:8080, the user clicks a button which calls this function.
authenticate = () => {
axios.get('/login')
.then(data => console.log(data));
}
Which calls this endpoint on localhost:3000.
router.get('/', (req, res) => {
let scopes = 'user-read-private user-read-email';
let client = process.env.SPOTIFY_CLIENT;
let redirect = 'http://localhost:3000/login/redirect';
res.redirect(`https://accounts.spotify.com/authorize?response_type=code'
&client_id=${client}${scopes ? `&scope=${encodeURIComponent(scopes)}` : ''}
&redirect_uri=${encodeURIComponent(redirect)}&state=${state}`);
});
When I click the login button on my front-end, I get this response, which I believe to be from Spotify as I can successfully make cross-origin requests to other endpoints in my API.
Failed to load... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
However, when I manually navigate to localhost:3000/login, the redirect works and I'm sent to the Spotify authentication page.
In addition, I tested trying to redirect my front-end to any url, and it doesn't work.
So my question is, how can I redirect my front-end through an API call from a server that doesn't also serve my static front-end content?
The reason this isn't working is because your axios.get('/login') is an AJAX request to your server which your server is then telling the AJAX request to be redirected to Spotify, but Spotify doesn't have your front-end server registered so you get the CORS error, since your request was initiated while on the front-end server URL.
Your AJAX request is following that redirect that was given, not trying to load your browser on http://localhost:3000, which would then redirect it to the Spotify authorization page.
Now, rather than doing:
authenticate = () => {
axios.get('/login')
.then(data => console.log(data));
}
You could do:
authenticate = () => {
window.location.href = "http://localhost:3000"
}
This would direct your front-end application to visit the URL of your API server and follow the redirect immediately to Spotify and then you could authorize and be redirected back to your API server, which could then redirect back to your front-end application.
Truthfully, this is a bit overkill, since presumably your React application and node application look like they would be running on the same domain outside of development, given the relative URL's you're using. If you're using create-react-app, you should follow their instructions on configuring your proxy via this or manually via this.
tl;dr you need to tinker with how your proxy is configured or change from doing an AJAX request there to actually going directly to /login (not doing an AJAX request).

How to add facebook authentication to my react app?

I'm using express as backend. I implemented facebook authentication at the backend.
router.get('/login/facebook',
passport.authenticate('facebook',{scope:['email']}));
router.get('/login/facebook/callback',
passport.authenticate('facebook',{
successRedirect : '/home',
failureRedirect:'/'
})
);
Now I want to call this through my react app, so that when the user lands up at home page, first he should be authenticated by facebook then only he can see homepage. How can I do this ?
I tried using react-router, but I can't understand how to call backend using react-router.
I also fetched /login/facebook using fetch command :
componentDidMount(){
fetch("127.0.0.1:3001/login/facebook");
But it gave me CORS error.
My react app is at 127.0.0.1:3000 and express server at 127.0.0.1:3001.
If this issue is only in dev mode, then Daniel's answer is correct.
In any case, I recommend to avoid calling the :3001 api directly from the :3000 app. Here's what I would do.
I will edit the fetch call as follows,
componentDidMount(){
fetch("/login/facebook");
}
This call will be received by the backend which serves the react application.
Now there are three cases,
Case 1: Your file serving app will have a proxy method which can forward requests to an API. For example read it here
Case 2 This is my Recommended approach. I would simply write the authentication logic in the :3000 server and only use the :3001 API for handling business logic of the app.
Case 3: If you have a backend app (:3000), say written using expressJs, you can forward the request to the :3001 API. Here is a sample code for that,
client.send({
method: req.method,
path: req.url,
data: req.body,
params: req.params
}).then( (response) => {
// Something
}).catch( (err) => {
// Handle error
});
Here the client is a module which uses the request module to make HTTP calls.
You can implement the above call as an express middleware to use it for all HTTP calls.
There are several options:
If you are using webpack dev server, you can set up a proxy to your api. See here
You can temporary disable cors validation during development. See here

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I am using nodejs server, express framework and fetch library to send request to another server which is in different domain. For one of my endpoint consider (localhost:8080/login) i am rendering ejs file when the user clicks login button i am sending a fetch request to an api (https:otherserver.com/login) different server which is in other domain. i am not able to send this request. I am getting this error :
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 404. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I am not sure how to handle this issue. please suggest some ideas or links which can solve this issue.
You can use cors middleware on your server.
Simplest way to use it is to add :
app.use(cors())
before all of your route handlers.
I found the solution for my problem. I am trying to explain what i understood as i am a beginner in server side and web development.
This was the problem i faced :
For one of my endpoint in my nodejs server, consider (localhost:8080/login) i am rendering ejs file when the user clicks login button in that ejs file, i am sending a fetch request to an api (https:otherserver.com/signin) of different server which is in other domain. i am not able to send this request. I was getting cors problem.
Cors problem was occuring because the server domain(my nodejs server) which rendered the ejs file and the other domain(https:otherserver.com/signin) to which i was making fetch request after clicking login button was different.
so solution was :
I need to make the fetch request first to the same domain(my nodejs server localhost:8080/api/signin). And then from this server i should call the api of other domain(https:otherserver.com/signin). By doing this we wont get any cors issue. Because the client side ejs file is requesting to the same server which has rendered the file. And then the server is bypassing the request to the other server.
code from client side javascript file. /api/signin is an endpoint in my local nodejs server and u can add the options:
options ={
method : 'POST',
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
body : JSON.stringify({
email_address : emailId,
password : pwd
})
};
fetch("/api/signin",options)
.then(function(res) {
console.log(res);
}).catch(function(error) {
console.log(error);
});
code from local nodejs server side:
express.use('/api/', function (req, res, next) {
var options = {
method : req.method,
headers :req.headers,
body : JSON.stringify(req.body)
};
fetch('https://otherserver.com'+req.path,options)
.then(response => {
return response.json();
}, error => { console.error(error)})
.then(function(json){
res.send(json);
})
.catch(function(error) {
res.send(error);
});
})
Hope this may help someone who is beginner in server development.

Trying to redirect client to Google OAuth, getting 405 error

I'm try to create a Web Service that connects to the Google Calendar API. In attempting to authorize my app, I have generated a url with necessary scopes. The problem is when I try to redirect the client to the generated url, I am getting a 405 error with the following message:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8080' is therefore not allowed
access. The response had HTTP status code 405.
For the most part I have been following this guide: https://developers.google.com/identity/protocols/OAuth2WebServer using the node.js client library.
From what I understand, it seems that Google has not configured their server to accept cross origin requests, what I don't understand is how I am supposed to redirect my users to their authorization page if I cannot send a request from my domain.
Here's the relevant code:
export function authorize(req, res, callback): any {
let auth = new googleAuth();
let oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
if (// Check if we have previously stored a token.) {
oauth2Client.credentials = //get token;
callback(oauth2Client);
} else {
//redirect to google authentication page
let authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
state: '/',
scope: SCOPES
});
res.redirect(authUrl);
}
}
Turns out when AJAX receives a 300 status code, the browser will automatically send another GET request to the returned location on behalf of the client. Even if I had gotten around my CORS issue I would have then had to manually load the html page myself since the request was made on behalf of the client. What I really want is for the browser to make the request to the auth uri.
So my solution to this problem is to detect redirects on the front end and have the browser issue a completely new GET request. Still seems like a work around so if anyone else has a better solution I'd like to hear it.
If some one use React or similar SPA Framework to solve this problem related to OAuth 2 read this:
Do not redirect on the server side. Don not do this (node.js/express as backend example):
router.get('/go', errorHandler(async (req, res, next) => {
res.redirect(authenticationUrl);
})
);
DO THIS:
router.get('/go', errorHandler(async (req, res, next) => {
res.json({
redirectUrl: 'https://google.com'
})
})
);
And then on your frontend client, get the response and make redirect. Example:
getUrl = async () => {
try {
const res = await API.get(`/go`);
window.location = res.data.redirectUrl;
} catch (err) {
console.log(err);
}
}
Work in React. Checked!
As per the flow, it is shown like Browser (APP) -> API (Server) -> Google auth (redirection), It is a very common trail with Identity provider servers like AWS, Google Auth, etc.. as they never send an additional header of ALLOW ORIGIN that's why browser reject the request when it comes to the point of redirection
Now comes the workout solution.
The App domain (http://localhost:3000) should be added as a trusted domain at the IDP server
Request to API server for Auth initiation should be
window.location.href = 'http://localhost:5000/api/v1/auth/login-google';

Resources