I am creating a login strategy for my angular 6 web app. The user clicks the login button and it triggers an HTTP request to localhost:3000/login on my node server. I am using okta as an authenticator and using the passport oidc strategy. If I go to localhost:3000/login it performs the redirect as expected to the okta sign-in the portal. When I try it from my angular front end I get a CORS error. I have enabled Access-Control-Allow-Origin with a wildcard.
//app.js
require("dotenv").config();
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const routes = require("./routes/routes");
const mongoose = require("mongoose");
const casperRoutes = require("./routes/casper-routes");
const oktaRoutes = require("./routes/okta-routes");
const slackRoutes = require("./routes/slack-routes");
const session = require("express-session");
const passport = require("passport");
const OidcStrategy = require("passport-openidconnect").Strategy;
const oktaBaseAuth = process.env.OKTA_AUTH_URI;
mongoose
.connect(
"mongodb+srv://xxxxx",
{ useNewUrlParser: true }
)
.then(() => {
console.log("connected to database!");
})
.catch(() => {
console.log("connection failed");
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-requested-With, Content-Type, Accept"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, PUT, DELETE, OPTIONS, PUT"
);
next();
});
app.use(
session({
secret: "xxx",
resave: false,
saveUninitialized: true
})
);
app.use(passport.initialize());
app.use(passport.session());
passport.use(
"oidc",
new OidcStrategy(
{
issuer: oktaBaseAuth + "/oauth2/default",
authorizationURL: oktaBaseAuth + "/oauth2/default/v1/authorize",
tokenURL: oktaBaseAuth + "/oauth2/default/v1/token",
userInfoURL: oktaBaseAuth + "/oauth2/default/v1/userinfo",
clientID: process.env.OKTA_AUTH_CLIENT_ID,
clientSecret: process.env.OKTA_AUTH_CLIENT_SECRET,
callbackURL: 'http://localhost:3000/authorization-code/callback',
scope: "openid profile"
},
(issuer, sub, profile, accessToken, refreshToken, done) => {
return done(null, profile);
}
)
);
passport.serializeUser((user,next)=>{
next(null,user);
});
passport.deserializeUser((obj,next)=>{
next(null,obj);
});
app.use('/login', passport.authenticate('oidc'));
app.use('/authorization-code/callback',
passport.authenticate('oidc', {failureRedirect: '/error'}),
(req,res)=>{
res.redirect('/');
});
function checkLogged(req,res,next){
if (req.isAuthenticated()){
return next();
}
res.redirect('/login');
}
app.use("/api/casper",checkLogged, casperRoutes);
app.use("/api/data",checkLogged, routes);
app.use("/api/okta", checkLogged,oktaRoutes);
app.use("/api/slack", checkLogged, slackRoutes);
module.exports = app;
The front end service
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Subject, Observable } from "rxjs";
import * as OktaSignIn from "#okta/okta-signin-widget";
import { Injectable } from "#angular/core";
import { Router } from "#angular/router";
#Injectable({
providedIn: "root"
})
export class OktaService {
widget;
isAuthenticated = false;
user;
private headers = new HttpHeaders();
private authStatusListener = new Subject<boolean>();
constructor(private http: HttpClient, private router: Router) {}
loginUser(){
this.http.get('http://localhost:3000/login').subscribe(res=>console.log(res));
}
}
And the error
Failed to load https://dev-795809.oktapreview.com/oauth2/default/v1/authorize?response_type=code&client_id=0oag898j7zj7j8jqw0h7&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthorization-code%2Fcallback&scope=openid%20openid%20profile&state=rtFMOtsHHBOc90UcM3nLIz%2Fp: Redirect from 'https://dev-795809.oktapreview.com/oauth2/default/v1/authorize?response_type=code&client_id=0oag898j7zj7j8jqw0h7&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauthorization-code%2Fcallback&scope=openid%20openid%20profile&state=rtFMOtsHHBOc90UcM3nLIz%2Fp' to 'https://dev-795809.oktapreview.com/login/login.htm?fromURI=/oauth2/v1/authorize/redirect?okta_key=c8hyLEuNV3KeYJyLfw2EU9xDjqsqeSOLft2jLzh-07E' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
I've enabled CORS on my OKTA app as well. I read somewhere this may be because I cannot resolve CORS with a wildcard for authorization data. How can I connect to the backend for login using angular front-end running on a different port?
This happens because you're trying to make an XHR request to your backend. If you change it to redirect to your backend, it should work.
loginUser() {
window.location.href = 'http://localhost:3000/login'
}
The problem with this approach is that you'll likely be redirected back to your Node app after successfully logging in, rather than your Angular app. You could write custom code in your Node app to redirect back to the referrer after authentication. I've done this with Spring Security, but I'm not sure how to do it for Node.
Another option would be to use our Angular SDK and do the authentication in your Angular app, and set up your Node API as a resource server that simply validates the access token that's passed in.
Related
I have implemented local as well as google login using passport.js in a mern web application. The local authentication is working fine with the frontend but I am getting errors when using the Google strategy.
Error:
Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?.........' (redirected from 'http://localhost:5000/auth/google') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:84)
Issue shown by the console:
Indicate whether a cookie is intended to be set in a cross-site context by specifying its SameSite attribute.
Indicate whether to send a cookie in a cross-site request by specifying its SameSite attribute
I tested the google strategy using POSTMAN and it was working fine but when requesting from my frontend there seems to be some issue.
server.js
require("dotenv").config();
const express=require("express");
const cors=require("cors");
const mongoose=require("mongoose");
const session=require("express-session");
const passport=require("passport");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const errorController=require("./controllers/errorController")
const app=express();
const port = process.env.PORT || 5000;
app.use(
cors({
origin: "http://localhost:3000", // <-- location of the react app were connecting to
credentials: true,
})
);
app.use(express.static("public"));
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(session({
secret:process.env.SECRET,
resave:false,
saveUninitialized:false,
}));
app.use(passport.initialize());
app.use(passport.session());
const User=require("./models/user.model");
passport.use(User.createStrategy());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:5000/auth/google/keeper"
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile);
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
mongoose.connect(process.env.MONGO_URI, {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify:false, useCreateIndex:true});
const connection = mongoose.connection;
connection.once('open', () => {
console.log("MongoDB database connection established successfully");
});
const loginRouter=require("./routes/login");
const registerRouter=require("./routes/register");
const logoutRouter=require("./routes/logout");
const authRouter=require("./routes/auth");
app.use("/login", loginRouter);
app.use("/register", registerRouter);
app.use("/logout", logoutRouter);
app.use("/auth/google", authRouter);
app.use(errorController);
app.listen(port, function(){
console.log("server started on port 5000");
});
auth.js (handles the google login related routes)
const router=require("express").Router();
const passport=require("passport");
router.get("/", passport.authenticate("google", { scope: ["profile"] }));
router.get("/keeper",
passport.authenticate("google", { failureRedirect: "/login" }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect("/");
});
module.exports=router;
Axios request from the frontend
function googleLogin(event){
Axios({
method: "GET",
withCredentials: true,
url: "http://localhost:5000/auth/google",
})
.then(function(res){
console.log(res);
})
.catch(function(err){
console.log(err);
})
event.preventDefault();
}
button that triggers the request
<button className="btn btn-danger" onClick={googleLogin}>Sign in with Google</button>
You can't make an axios call to the /auth/google URL!!
Here's my solution...
// step 1:
// onClick handler function of the button should use window.open instead
// of axios or fetch
const googleLogin = () => window.open("http://[server:port]/auth/google", "_self")
//step 2:
// on the server's redirect route add this successRedirect object with correct url.
// Remember! it's your clients root url!!!
router.get(
'/google/redirect',
passport.authenticate('google',{
successRedirect: "[your CLIENT root url/ example: http://localhost:3000]"
})
)
// step 3:
// create a new server route that will send back the user info when called after the authentication
// is completed. you can use a custom authenticate middleware to make sure that user has indeed
// been authenticated
router.get('/getUser',authenticated, (req, res)=> res.send(req.user))
// here is an example of a custom authenticate express middleware
const authenticated = (req,res,next)=>{
const customError = new Error('you are not logged in');
customError.statusCode = 401;
(!req.user) ? next(customError) : next()
}
// step 4:
// on your client's app.js component make the axios or fetch call to get the user from the
// route that you have just created. This bit could be done many different ways... your call.
const [user, setUser] = useState()
useEffect(() => {
axios.get('http://[server:port]/getUser',{withCredentials : true})
.then(response => response.data && setUser(response.data) )
},[])
Explanation....
step 1 will load your servers auth url on your browser and make the auth request.
step 2 then reload the client url on the browser when the authentication is
complete.
step 3 makes an api endpoint available to collect user info to update the react state
step 4 makes a call to the endpoint, fetches data and updates the users state.
I have a setup as such:
-backend
-model
--User.js
-routes
--auth.js
-database
--connection.js
-passport
--passport.js
--server.js
-client
-react folders / files
...
In my server.js:
const express = require("express");
const cookieSession = require("cookie-session");
const passport = require("passport");
const { authRoutes } = require("./routes/auth");
require("./model/User");
require("./services/passport");
require("./services/mongoConnect");
const app = express();
app.use(
cookieSession({
maxAge: "30 * 24 * 60 * 60 * 1000",
keys: "MY-KEY",
})
);
app.use(
cors({
origin: true,
methods: "GET, POST, PATCH, DELETE, PUT",
allowedHeaders: "Content-Type, Authorization",
})
);
app.use(passport.initialize());
app.use(passport.session());
const PORT = process.env.PORT || 5000;
app.use("/", authRoutes);
app.listen(PORT);
Inside my auth.js file inside my router
const passport = require("passport");
const router = require("express").Router();
router.get(
"/auth/google",
passport.authenticate("google", {
scope: ["profile", "email"],
})
);
router.get("/auth/google/callback", passport.authenticate("google"));
router.get("/api/logout", (req, res) => {
req.logout();
res.send(req.user);
});
router.get("/api/current_user", (req, res) => {
res.send(req.user);
});
module.exports = {
authRoutes: router,
};
Inside passport.js file I have
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const mongoose = require("mongoose");
const User = mongoose.model("users");
passport.use(
new GoogleStrategy(
{
clientID: "MY-ID",
clientSecret: "MY-SECRET",
callbackURL: "/auth/google/callback",
proxy: true,
},
(accessToken, refreshToken, profile, done) => {
User.findOne({ googleId: profile.id }).then((existingUser) => {
if (existingUser) {
done(null, existingUser);
} else {
new User({
googleId: profile.id,
})
.save()
.then((newUser) => {
done(null, newUser);
});
}
});
}
)
);
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then((user) => {
done(null, user);
});
});
My frontend consists of a button that hits my auth/google route. However it logs a cors issue error in the console.
(redirected from 'http://localhost:3000/auth/google') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Doea anyone know how i can solve this? In mu google console I have the redirect url setup as 'http://localhost:3000/auth/google/callback'
First you need to update the cors origin with '*' or your client specific whitelisted url. But that alone is not going to solve the problem.
your button should load the auth url on the browser instead of making an api call to the auth/google route. So you can make the button a href link instead.
You have misconfigured CORS on your backend.
First, you are using wrong syntax when it comes to methods - there should be no spaces when you are listing them (I don't know how they are parsing the string but you should probably stick with the documentation -
according to documentation, you can specify methods either as a string: 'GET,PUT,POST' or a list: ['GET', 'PUT', 'POST'].
Second, you are missing OPTIONS HTTP method in the methods which is used by browsers in preflight request to test server's CORS configuration.
Third, are you sure about the specified headers?
The easiest option is to drop the CORS options configuration completely if you are not sure what you are doing and apply the cors globally before every request.
app.use(cors());
Or to only specific path where you want to allow CORS.
app.get("/somepath", cors(), (req, res) => {...
Maybe you didn't configure cors policy in your backend.
The most simple way is to install cors package if you use Express.
npm install cors
And use it as a middleware of your express app.
var app = express()
var cors = require('cors');
...
app.use(cors());
The problem is even though you have used cors package you have not added the following Access-Control-Allow-Origin option in cors. Try this :
app.use(
cors({
origin: '*',
methods: "GET, POST, PATCH, DELETE, PUT",
allowedHeaders: "Content-Type, Authorization",
})
);
Or as yash has mentioned simply use:
app.use(cors())
For more reference check the official npm cors documentation
I'm currently running a webserver using the MERN stack, and I'm trying to get OAuth login working properly. However, when I click the "login with google" button, react loads the homepage (but the URL changes). Fetching the URL directly gets a 302 response from the server, but my front-end doesn't change.
Server.js
const express = require('express');
const path = require('path');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const logger = require('morgan');
const cors = require('cors');
const secure = require('express-force-https');
const passport = require('passport');
const cookieSession = require('cookie-session');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 5000;
const dbRoute = process.env.MONGODB_URI || 'NO DB ROUTE PROVIDED';
// db setup
mongoose.connect(
dbRoute,
{
useNewUrlParser: true,
useUnifiedTopology: true,
dbName: process.env.DATABASE_NAME,
}
);
let db = mongoose.connection;
db.once('open', () => console.log("Connected to the database"));
db.on('error', console.error.bind(console, "MongoDB connection error: "));
// middleware
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false })); // body parsing
app.use(bodyParser.json());
app.use(logger("dev"));
app.use(express.static(path.join(__dirname, "client", "build"))); // for serving up the clientside code
app.use(secure); // ensure that the connection is using https
app.use(cookieSession({ // cookies!
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
keys:['vcxzkjvasddkvaosd'] // yeah i'm sure that's secure enough
}));
// models
require('./models/rule');
require('./models/affix');
require('./models/user');
// passport security
require('./config/passport');
app.use(passport.initialize());
app.use(passport.session());
// routes
app.use(require('./routes'));
// The "catchall" handler: for any request that doesn't
// match one above, send back React's index.html file.
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
app.listen(port);
console.log(`Server listening on ${port}`);
Route (There are a few index files in different folders, so the full path for this route it /api/user/google)
const mongoose = require('mongoose');
const passport = require('passport');
const router = require('express').Router();
const auth = require('../auth');
const User = mongoose.model('User');
router.get('/google',
passport.authenticate('google', {
scope: ['profile', 'email']
})
);
router.get('/google/callback',
passport.authenticate('google', { failureRedirect: '/affixes'}),
(req, res) => {
res.redirect('/?token=' + req.user.token);
}
);
Passport.js
const mongoose = require('mongoose');
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
require('dotenv').config();
const User = mongoose.model('User');
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id).then((user) => {
done(null, user);
})
});
passport.use(new GoogleStrategy({
clientID: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_CLIENT_SECRET,
callbackURL: '/api/user/google/callback',
proxy: true
},
(accessToken, refreshToken, profile, done) => {
User.findOne({ googleId: profile.id })
.then((existingUser) => {
if (existingUser) {
done(null, existingUser);
} else {
new User({ googleId: profile.id }).save()
.then((user) => done(null, user));
}
});
}
));
Frontend login page (has a fetch button and a link button. As described above, different behavior)
import React from 'react';
import {
ComingSoon
} from '../Common';
import {
Button
} from '#material-ui/core';
const handleClick = () => {
fetch('/api/user/google')
}
export default function Login() {
return (
<>
<Button onClick={handleClick}>
Login with Google
</Button>
<button>Log in with Google</button>
</>
);
}
Update: Looks like some kind of CORS issue, although I still don't know how to fix it. Browser spits out
Access to fetch at '...' (redirected from 'http://localhost:3000/api/user/google') from origin 'http://localhost:3000' has been blocked by CORS policy: 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.
Adding the requested header gives me
Access to fetch at '...' (redirected from 'http://localhost:3000/api/user/google') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
It turns out I was quite wrong about the nature of this issue! The problem was that my fetch requests to my OAuth endpoint were calling my frontend, not my backend because the request included text/html in its Accept header. Using the react advanced proxy setup to route to the proper URI fixed the issue.
See: https://github.com/facebook/create-react-app/issues/5103 and https://github.com/facebook/create-react-app/issues/8550
I have a GraphQl server and a react frontend. I use passport and LocalStrategy to authenticate the user which works well, I can successfully login an existing user. I also want to use passport session to create a user session, so that I can access the logged in user later in my GraphQl resolvers for authentication. I expected passport to set the user in the session after successfully authenticating one. But after sending correct credentials from the client to the server, GraphQl queries do not have access to req.user.
The GraphQL server code looks like this:
import express from 'express';
import passport from 'passport';
import {Strategy as LocalStrategy} from 'passport-local';
import session from 'express-session';
import cors from 'cors';
import bodyParser from 'body-parser';
import models from './models';
import typeDefs from './schema';
import resolvers from './resolvers';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import { makeExecutableSchema } from 'graphql-tools';
export const schema = makeExecutableSchema({
typeDefs,
resolvers,
});
const app = express();
app.use('*', cors({ origin: 'http://localhost:3000' }));
app.set('port', (process.env.PORT || 3001));
//--- Passport ----
app.use(session({
saveUninitialized: true,
resave: false,
secret: 'verysecretsecret'
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
passport.use(new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
},
function(email, password, done) {
models.User.findOne({
where: {
email: email
}
}).then(function(user) {
if (user) {
if (user.validPassword(password)) {
return done(null, user);
} else {
return done(null, false);
}
}
return done(null, false);
});
}
));
//--- Routes ----
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql'
}));
app.use(
'/graphql',
bodyParser.json(),
graphqlExpress( (req) => {
console.log('/graphql User: ' + req.user); // prints undefined after sending correct login credentials to /login
return ({
schema,
context: {
user: req.user,
},
});}),
);
app.use(bodyParser.urlencoded({ extended: true }) );
app.post('/login', passport.authenticate('local'), (req, res) => {
console.log('/login: User', req.user); // prints the logged in user's data
return res.sendStatus(200);
});
export default app;
And this is the login fetch request from the client:
onSubmit = () => {
var details = {
'email': this.state.email,
'password': this.state.password,
};
var formBody = [];
for (var property in details) {
var encodedKey = encodeURIComponent(property);
var encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");
fetch('http://localhost:3001/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
credentials: 'include',
body: formBody
}).then(function(response) {
console.log(response);
}).catch(function(err) {
// Error
});
};
Do I have to change something on the client side for the server to receive the session cookie? Or is something going wrong in the backend?
I also uploaded a minimal example to this repo: https://github.com/schmitzl/passport-graphql-minimal-example
Managing sessions gets a little messy when you're dealing with CORS. There's a couple of things you need to change to get the behavior you're expecting:
First, modify your server code to ensure you're sending the Access-Control-Allow-Credentials header:
app.use('*', cors({ origin: 'http://localhost:3000', credentials: true }));
Next, make sure your requests are actually including the cookies. You've done so with the login request, by setting the credentials option to include. Apollo uses fetch under the hood and we need to pass this option to it as well.
I may be missing something, but it doesn't appear that apollo-boost provides an easy way to do the above (you have fetchOptions, but including credentials there doesn't appear to do anything). My advise would be to scrap apollo-boost and just use the appropriate libraries directly (or use apollo-client-preset). Then you can pass the appropriate credentials option to HttpLink:
import ApolloClient from 'apollo-client'
import { HttpLink, InMemoryCache } from 'apollo-client-preset'
const client = new ApolloClient({
link: new HttpLink({ uri: apolloUri, credentials: 'include' }),
cache: new InMemoryCache()
})
I am using Node.js with express server, and passport package for authentication. Client is on same server, different domain built on Backbone.js. The session is created on login request, but if another request comes from client side, I don't manage to access the session.
Node server configuration:
var express = require( 'express' ),
path = require( 'path' ),
mongoose = require( 'mongoose' ),
passport = require('passport'),
cors = require('cors');
app.configure( function() {
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({
secret: secret,
key: key,
cookie : {
maxAge: maxAge
}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use( express.methodOverride() );
app.use( app.router );
app.use( express.static(application_root) );
app.use(cors());
});
Logging in and auth check:
app.post('/login', cors(corsOptions), passport.authenticate('login', {
successRedirect : successDirect,
failureRedirect : failureDirect
}));
function requireAuth(req, res, next) {
if(req.session.user) {
next();
}
else if (req.cookies.isAuthenticated) {
next();
} else {
res.redirect(loginUrl);
}
}
On login, the session is created. If I send any requests from the server side (localhost:9999/anymethod), then the session is accessed, responses accordingly. If I try to send a request from client side to the same url, then the session is always 'undefined'.
Example:
app.get('/mymethod', cors(corsOptions), requireAuth, function(request, response) {
return response.send("Done");
});
This method works when accessed from server after logging in, but not when accessed from client side (client is established on same server, different domain).
Added to Backbone.js:
initialize: function() {
this.collection.fetch({reset: true, beforeSend: this.beforeFetch});
},
beforeFetch: function(xhr) {
xhr.withCredentials = true;
},...
Edit: The request coming from client doesn't contain any cookies.
How can I access the session created by passport after logging in, sending a request from client?
I guess cors library does it (i haven't used that library). But if it doesn't then in server side
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next();
});
And in client ajax request
xhrFields: {
withCredentials: true
}