NodeJs configured and running fine with passportJS OAuth2, but the requirement is angular should call node api, both are runs in different ports, calling all nodeJS's rest API from angular and it runs fine using proxy.conf.json, while calling /googleauth/redirect from angular getting error response.
Response :
Failed to load https://accounts.google.com/o/oauth2/v2/auth?response_type=code... No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.
Google API Setting :
Restrictions
Authorised JavaScript origins :
http://localhost:4200
http://localhost:8088
Authorised redirect URIs :
http://localhost:4200/api/googleauth/redirect
http://localhost:8088/api/googleauth/redirect
Update 1 : CORS to app.js (new): but no changes.
var cors = require('cors');
var app = express();
app.use(cors());
app.options('*', cors());
app.use('/api',cors(),require('./routes/api'));
Update 2 : api.js
router.get('/google', passport.authenticate('google', { scope: ['profile','email'] }));
passport setup
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20');
const userModel = require('../model/user');
passport.serializeUser((user,done)=>{
done(null,user.id);
});
passport.deserializeUser((id,done)=>{
userModel.findById(id).then((user)=>{
done(null,user);
})
});
passport.use(
new GoogleStrategy({
callbackURL:'/api/googleauth/redirect',
clientID:'',
clientSecret:''
},(accessToken,refreshToken,profile,done) =>{
console.log("call back function fired");
//console.log(accessToken);
userModel.findOne({email:profile.emails[0].value,authType:'google'},function(err,user){
if(user){
done(null,user);
}else{
done(null,user);
}
});
}))
I resolved this problem with a tutorial https://medium.com/#ahsan.ayaz/how-to-handle-cors-in-an-angular2-and-node-express-applications-eb3de412abef
Only lack a detail... next to the lines
import { BrowserXhr } from ‘#angular/http’;
and
import {CustExtBrowserXhr} from ‘./app/path-to-file/cust-ext-browser-xhr’;
you should add
import { LocationStrategy, HashLocationStrategy } from '#angular/common';
Related
I have a Next.js app hosted on Vercel at www.example.com, which needs to communicate with a backend .NET Core Web API hosted on a different server at api.example.com.
The .NET core web api has been configured to allow CORS but my Next.js keeps complaining that data cannot be displayed when I use AXIOS to fetch data because the response lacks allow-cors headers:
Access to XMLHttpRequest at 'https://api.example.com' from origin 'http://www.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource
It works fine when I run it locally using npm run dev, but doesn't work when I build it and then run npm run start
Does anyone know how to fix the cors issue in production?
I found a solution here:
Basically, I just need to add a next.config.js file in the root directory and add the following:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
]
},
};
if you want to use the cors library in nextjs, I created a library for it is nextjs-cors.
https://www.npmjs.com/nextjs-cors
https://github.com/yonycalsin/nextjs-cors
pages/api/whoami.{ts,js}
import NextCors from 'nextjs-cors';
async function handler(req, res) {
// Run the cors middleware
// nextjs-cors uses the cors package, so we invite you to check the documentation https://github.com/expressjs/cors
await NextCors(req, res, {
// Options
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
origin: '*',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
});
// Rest of the API logic
res.json({ message: 'Hello NextJs Cors!' });
}
it was a problem in the server not accepting OPTIONS requests, because routes were declared as GET::something or POST:: something, so the preflight couldn't pass and the POST request was decliend, hope this will help another people to prevent hours of googling, so in my case (Node.js + Express.js) i had to add this to my server.js
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method == "OPTIONS") {
res.header("Access-Control-Allow-Methods", "PUT, POST, PATCH, DELETE, GET");
return res.status(200).json({});
}
next();
});
I had a similar issue, I was making the call from this page:
pages/page1.js
export default async function page1() {
const data = await axios.post('https://www.dominio.com/xxx' , {param: 1}, headers)
}
But the solution is to make axios calls to a local API file inside "pages/api" directory, and this local API file, will handle the request to the external webserver. This avoid the CORS issue.
pages/page1.js
export default async function page1() {
const data = await axios.post('/api/get_page1_data', {param: 1} )
}
pages/api/get_page1_data.js
export default async function handler(req, res) {
try{
const data = await axios.post('https://www.dominio.com/xxx' , {param: req.body.param}, headers)
res.status(200).json(data)
} catch (error) {
console.error(error)
return res.status(error.status || 500).end(error.message)
}
Do an extra check if your base URL is correct that was my issue
In my case, the preflight request was failing due to an agressive HTTP method filter.
Make sure that you specify
// Preflight Check:
if (req.method == "OPTIONS") {
res.setHeader("Allow", "POST");
return res.status(202).json({});
}
// Allow only POST Methods
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
return res.status(405).json({ error: `Method ${req.method} Not Allowed` });
}
You can allow all methods with https://vercel.com/support/articles/how-to-enable-cors#enabling-cors-in-a-next.js-app, but make sure that each endpoint returns a 2XX status code for the OPTIONS HTTP method.
Please make sure it is CORS and is not something else. For example, in my case I was getting a 400 response. Please look on the Response tab of that request for information.
after hours of googleing i found the solution on the next-docs itself!!!
see the following repository on github
API Routes Example with CORS
https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors
I had this issue taking a SoloLearn NestJS course and it was resolved by adding the line: app.enableCors() in main.ts file on the root folder in the NESTJs Project.
The file was like this:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3000);
}
bootstrap();
I have Next.js application that has graphql and Apollo Client setup (apollo version : 3.5.10). In order to make a query inside any component you have to use "client" variable that Apollo Client provide. You need to have apollo-client.js file in your project root so that Apollo Client can use it inside any component for query. Inside any component when you trying to make a query like: client.query(...), with these settings of apollo-client file it will throw "cors" error. However you can fix this by adding headers property inside apollo-client file.
This is OLD Settings:
apollo-client.js (old)
import { ApolloClient, InMemoryCache } from '#apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
export default client;
This is NEW Settings:
apollo-client.js (new)
import { ApolloClient, InMemoryCache } from '#apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
headers: {
fetchOptions: {
mode: 'no-cors',
},
},
});
export default client;
By doing this, you won't get any "cors" error while doing query inside any component.
I have a CORS problem with axios.
The server is fine, I am sending Access-Control-Allow-Origin: * on all routes.
I can even login using the same backend, but for some reason logout is not working, axios can't see the headers.
I made a video:
https://youtu.be/vHfyk8BteLA
Can somebody explain that? When I check the network with a GET on the browser the header is there, but when the get is triggered by axios the header vanishes.
logout = () => {
const token = window.localStorage.getItem('jwt_access_token');
const request = axios.post('https://localhost/vintiapi/public/api/logout?token='+token);
this.setSession(null);
request.then(response => {
console.log('logout');
});
};
The error message suggests that it's the preflight request that's not getting the header. If you're using the cors module, you'll need to handle the OPTIONS request yourself:
// From: https://expressjs.com/en/resources/middleware/cors.html#enabling-cors-pre-flight
var express = require('express')
var cors = require('cors')
var app = express()
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
app.del('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('CORS-enabled web server listening on port 80')
})
Or you can enable it for all preflight requests:
app.options('*', cors())
I'm developing ReactJS application integrated with 3rd party API. I can successfully execute same requests with Postman, but they are being blocked when executing from React application in browser. I am aware about CORS and how to solve the problem when I refer my own backend, but in this case obvoiusly I cannot. I tried to do requests with several JS modules intended to do similar stuff, but got the same error for each.
Access to fetch at 'http://api.example.com/resource/request?param=value' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
import React, {Component} from 'react';
import fetch from 'fetch';
import request from 'request';
class App extends Component {
render() {
return (
<div className="App">
<button onClick={this.sendWithXmlHttpRequest}>send XMLHttpRequest
</button>
<button onClick={this.sendWithFetch}>send Fetch</button>
<button onClick={this.sendWithRequest}>send Eequest</button>
</div>
);
};
sendWithXmlHttpRequest = () => {
let req = new XMLHttpRequest();
req.open('get', url, true);
req.send();
};
sendWithFetch = () => {
fetch.fetchUrl(url, (error, meta, body) => {
console.log(error, meta, body);
});
};
sendWithRequest = () => {
request.get(url);
};
}
const url = 'http://api.example.com/resource/request?param=value';
export default App;
Assuming you are using Node for your backend. From the server side send the Access-Control-Allow-Origin header as * so that the client knows about the server policy.You can add cors npm package to do the job for you aswell. Below is the code on how I solved this on the express side:
app.use(function(req, res, next) {
res.header(“Access-Control-Allow-Origin”, “*”);
res.header(“Access-Control-Allow-Methods”, “GET,PUT,POST,DELETE”);
res.header(
“Access-Control-Allow-Headers”,
“Origin, X-Requested-With, Content-Type, Accept”
);
next();
});
app.options(“*”, cors());
Additionally you can install some CORS extension on the browser and enable requests.
One such extension
https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc
This fixes the problem, but I don't think it's something you are willing to include in a Production Ready application.
sendWithXmlHttpRequest = () => {
// Added a Proxied server which works as a middle-man to fetch the data for you.
const urlWithProxy = `https://cors-anywhere.herokuapp.com/${url}`
let req = new XMLHttpRequest();
req.open('get', url, true);
req.send();
};
This is from..
The preferrable way is just to have a server.js that serves your Bundled App and that may -odds are few- require some Request Policy, but, to my expectations it will be enough with no configuration since the request is going to be proxied via Node not React.
An Apollo server is setup, and it responds correctly to the query when using graphiql.
An existing react-redux app with server side rendering needs to start using graphql and make this query.
A component of this app has been setup to do the same query, it seems to be doing the network request, but it fails with
Error: {"graphQLErrors":[],"networkError":{},"message":"Network error: Failed to fetch"}
Any troubleshooting advice?
It really is cors issue. I tried to fix it by using express. But it didn't work with Apollo GraphQL.
const corsOptions = {
origin: "http://localhost:3000",
credentials: true
};
app.use(cors(corsOptions));
So, I tried configuring cors inside GraphQL server and It Worked.
For Apollo Server
const corsOptions = {
origin: "http://localhost:3000",
credentials: true
};
const server = new ApolloServer({
typeDefs,
resolvers,
cors: corsOptions
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
For GraphQL Yoga
const options = {
cors: corsOptions
};
server.start(options, () =>
console.log("Server is running on http://localhost:4000")
);
I was running apollo client on localhost, and apollo server on someDomain.com, so it was a CORS issue. After loading the page that does the query in chrome incognito mode and refreshing, this error was found in the chrome dev tools console:
httpLink.js:71 OPTIONS https://someDomain.com/graphql 405 (Method Not Allowed)
(anonymous) # httpLink.js:71
...
(index):1 Failed to load https://someDomain.com/graphql: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:8443' is therefore not allowed access. The response had HTTP status code 405. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
A quick fix for this (test only) setup was to setup cors on the express apollo server like this post suggests.
https://blog.graph.cool/enabling-cors-for-express-graphql-apollo-server-1ef999bfb38d
All you need to do to make the following work is to enable cors library for your Apollo-Graphql server
yarn add cors / npm install cors
Now got to you app.js or server.js ( Basically the entry file of your server )
add the following lines to it
const cors = require('cors');
app.use(cors()); // Make sure you have express initialised before this.
Try using the cors middleware at the top of your code. This initializes the cross-origin resource sharing first before the graphql endpoint is created.
enter const { urlencoded } = require("express");
const express = require("express");
const app = express(); //create an express application
const helmet = require("helmet"); //require helment from node modules
const cors = require("cors"); //cross-origin-resource sharing
const mR = require("./routes/main");
const schema = require("./graph-schema/schema");
const mongoose = require("mongoose");
//cross-origin-resources-sharing defined at the top before your graphql endpoint
app.use(
cors({
optionsSuccessStatus: 200, //option sucess status
origin: "http://localhost:3000", //origin allowed to access the server
})
);
//connect to database
mongoose.connect("mongodb://localhost:27017/Graphql_tutorial", {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
});
//graphql area
const { graphqlHTTP } = require("express-graphql"); //This allows express to understand graphql and lunch its api.
app.use(
"/graphql",
graphqlHTTP({
schema,
graphiql: true,
})
);//code here
You can have this error as well if you pass a null HEADER in your request through Apollo, so something like:
const middlewareLink = setContext(() => ({
headers: {
'authorization': `Bearer ${FeedierExchanger.token}` || null
}
}));
Change it to:
const middlewareLink = setContext(() => ({
headers: {
'authorization': `Bearer ${FeedierExchanger.token}` || ''
}
}));
Or remove this part:
|| ''
If you've the correct backend validation.
I am creating an api (server side) based on Meanjs.org latest version (0.4.0) and i managed to pull off only the MEN part and create one in http://localhost:3000/api
as the frontend part i created an Angularjs in http://localhost:4000/
and then i run both application using (P)ackage (M)anager 2
I am trying to create a user by sending user credentials using $resource like this
angular.module('users').factory('AuthenticationResource', ['$resource',
function($resource) {
return $resource('http://localhost:3000/api/auth/signup', {}, {
post: {
method: 'POST'
}
});
}
]);
...
//In my controller
$scope.signup = function() {
AuthenticationResource.post($scope.credentials, function(response) {
$scope.authentication.user = response;
$state.go($state.previous.state.name || 'home', $state.previous.params);
});
};
While in my server side's express.js
'use strict';
var config = require('../config'),
express = require('express'),
...
cors = require('cors');
...
module.exports.initModulesServerRoutes = function(app) {
// Globbing routing files
config.files.server.routes.forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
};
module.exports.initCorsOption = function(app){
app.options('*', cors());
};
module.exports.init = function(db) {
// Initialize express app
var app = express();
...
// Initialise Cors options
this.initCorsOption(app);
// Initialize modules server routes
this.initModulesServerRoutes(app);
...
return app;
};
I am using node cors package to enable cors and just do app.options('*', cors()); to enable pre-flight across-the-board
But when i am trying to do a POST to http://localhost:3000/api/auth/signup i can see that my user is being saved to the database just fine but it doesn't give me any response and chrome console is giving me this
XMLHttpRequest cannot load http://localhost:3000/api/auth/signup. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4000' is therefore not allowed access.
What did i miss?
I think you are missing app.use before all your routes:
Only express:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
If you are using npm cors:
app.use(cors());