// main.ts
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
// tried with config passed in
app.enableCors({ origin: true });
app.enableCors({ origin: '...' });
// tried setting it in the app
const app = await NestFactory.create(AppModule, { cors: true });
const app = await NestFactory.create(AppModule, { cors: { origin: true } });
const app = await NestFactory.create(AppModule, { cors: { origin: '...' } });
await app.listen(8080);
}
bootstrap();
I've tried every documented method of enabling CORS, none of them have worked.
I'm using NestJS with Express. The request is being sent by Axios.
The OPTIONS request is 404ing.
Related
I'm trying to create an authentification system using firebase, cloud function and express
I've follow this guide for my express app mixed with the Google Docs about cookies.
Here's my server code
index.ts
import { cors } from "./middlewares/cors";
import { initFirebase } from "./utils/firebase";
import { IRoutes } from "./interfaces";
import { routes } from "./routes";
import * as cookieParser from "cookie-parser";
import * as bodyParser from "body-parser";
import * as Express from "express";
import * as functions from "firebase-functions";
// firebase initialize
initFirebase();
// REST API routes
routes.forEach((routerObj: IRoutes) => {
const app = Express();
app.use(cookieParser());
app.use(cors);
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true
})
);
// export routes individually for cloud functions
app.use(routerObj.router);
exports[routerObj.name] = functions.region("europe-west1").https.onRequest(app);
});
cors.ts
import * as Cors from "cors";
const options: Cors.CorsOptions = {
credentials: true,
methods: "GET,OPTIONS,POST,DELETE,HEAD,PATCH",
preflightContinue: false,
origin: "*"
};
export const cors = Cors(options);
my api route for login
router.post("/login", async (req: Request, res: Response) => {
const { idToken } = JSON.parse(req.body).data;
// // Guard against CSRF attacks.
// if (csrfToken !== req.cookies.csrfToken) {
// res.status(401).send("UNAUTHORIZED REQUEST!");
// return;
// }
// Set session expiration to 5 days.
const expiresIn = 60 * 60 * 24 * 5 * 1000;
try {
const sessionCookie = await admin.auth().createSessionCookie(idToken, { expiresIn });
const options: CookieOptions = {
signed: false,
maxAge: expiresIn,
httpOnly: false,
secure: false
};
res.setHeader("Cache-Control", "private");
res.cookie("__session", sessionCookie, options);
res.status(200).send({ cookies: req.cookies });
} catch (e) {
console.error(e);
res.status(401).send("UNAUTHORIZED REQUEST!");
}
});
my api route to check connexion status
router.post("/status", async (req: Request, res: Response) => {
const sessionCookie = req.cookies.__session || "";
try {
const decodedClaims = await admin.auth().verifySessionCookie(sessionCookie!, true);
console.log("decodedClaims: ", decodedClaims);
res.end(JSON.stringify({ data: { decodedClaims } }));
// res.redirect("/profile");
} catch (e) {
console.error(e);
res.status(401).send("UNAUTHORIZED REQUEST!");
}
and then how I call the api from my client side (http://localhost:3001)
const idToken = await user.getIdToken();
try {
await fetch("http://localhost:5003/test/europe-west1/user/login",
{
method: "POST",
headers: {
ContentType: "application/json",
Accept: "application/json"
},
body: JSON.stringify({
data: {
idToken
}
})
}
);
} catch (e) {
console.error(e);
}
First point, no __session cookie's created with this code. However, the response of the request is
But nothing in the cookies section of the browser and when I try to get it with req.cookies.__session
Nevertheless if I try to fetch http://localhost:5003/test/europe-west1/user/login directly from the same origin, everything work
I suggest the problem come from cross-origin authorizations
I've checked a lot a issues about this
firebase cloud function won't store cookie named other than "__session"
Express - Firebase - Check undefined req.cookie.__session without throwing error
And more, but nothing work
I'm using Express & ReactJS
Express Code:
const Express = require('express');
const PORT = 5000;
const cors = require('cors');
const server = Express();
server.use(cors()); // I've added the cors
server.get('/users', (req, res) => {
res.send({"users": [ {"user1": "John"}, {"user2": "Nick"} ]);
})
server.listen(PORT, () => {
console.log("server is running on 5000")
});
React Code:
import { useState,useEffect } from 'react';
const Home = () => {
async function fetchData() {
try{
const output = await fetch(`http://localhost:5000/users`);
console.log(output);
} catch(e){
console.error(e);
}
}
useEffect(() => {
fetchData();
}, [])
}
return (
<h1>FetchData</h1>
)
export default Home;
After doing these things... I'm still getting the CORS error in my console.
Here's the full Error Message:
Response { type: "cors", url: "http://localhost:5000/users, redirected: false, status: 500, ok: false, statusText: "Internal Server Error", headers: Headers, body: ReadableStream, bodyUsed: false }
After doing some research, I've found that adding "proxy": "http://localhost:5000" in package.json file will solve the issue. But Nothing is happening.
What should i do now ?
Thanks :)
Try using axios instead of fetch:
// npm install axios
import { useState,useEffect } from 'react';
import axios from 'axios'
const Home = () => {
async function fetchData() {
try{
const output = await axios(`http://localhost:5000/users`);
console.log(output);
} catch(e){
console.error(e);
}
}
useEffect(() => {
fetchData();
}, [])
}
return (
<h1>FetchData</h1>
)
export default Home;
Try with cores options,
const corsOptions = {
origin: ['http://localhost:<port_of_reactapp>'],
methods: ['GET', 'POST', 'DELETE', 'UPDATE', 'PUT', 'PATCH'],
};
server.use(cors(corsOptions));
https://expressjs.com/en/resources/middleware/cors.html
If you already npm install cors, in your const server, change const server from const server = Express(); to const server = express();.
https://expressjs.com/en/resources/middleware/cors.html
Or try to use node-http-proxy then just requests from your local host:
http.createServer(function(req, res) {proxy.web(req, res, { target: 'http://localhost:5000/users' });});
Installation: https://github.com/http-party/node-http-proxy
I am using the npm cors package with my react app and express (OOP approach), but I still get the CORS error:
Access to XMLHttpRequest at 'http://localhost:8000/api/auth/authenticate' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have cors() set up on the backend, at localhost:8000. I am calling the api with { withCredentials: true } on the front end, at localhost:3000.
So I am not sure where did it go wrong.
My setup below. Thanks,
Backend - express.middleware.ts
import cors from "cors";
import express from "express";
module.exports = (app: any) => {
app.use(
cors({
origin: "http://localhost:3000",
methods: ["POST", "PUT", "GET", "OPTIONS", "HEAD"],
credentials: true,
})
);
app.use(express.static("public"));
};
Backend - app.ts
import express from "express";
import dotenv from "dotenv";
import path from "path";
class App {
private _app: express.Application;
private readonly _port: number | string = process.env.PORT || 8000;
constructor(controllers: any[]) {
this._app = express();
dotenv.config();
this.initializeControllers(controllers);
this.initializeMiddleWares();
}
public start() {
this._app.listen(this._port, () => {
console.log(`App listening on the port ${this._port}`);
});
}
private initializeControllers(controllers: any[]) {
controllers.forEach((controller) => {
this._app.use("/api", controller.router);
});
}
public initializeMiddleWares() {
require("./src/middleware/express.middleware")(this._app);
}
}
export default App;
Backend - server.ts
import App from "./app";
import AuthController from "./src/modules/auth/auth.controller";
import { AuthService } from "./src/modules/auth/auth.service";
const server = new App([new AuthController(new AuthService())]);
server.start();
Frontend - useGet.ts(custom hook to call api)
import React from "react";
import { useHistory } from "react-router-dom";
import axios from "axios";
import { server_url } from "../constants";
const useGet = () => {
const history = useHistory();
const doGet = (path: string, cb?: Function) => {
axios
.get(`${server_url}${path}`, { withCredentials: true })
.then((response) => {
if (cb) {
cb(response.data);
}
})
.catch((err) => {
console.log(err);
});
};
return [doGet];
};
export default useGet;
Initialize the middleware before configuring the routes.
From the docs:
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
In your case, the controllers do end the request-response cycle, thus the middleware never gets to act.
To fix it, change this:
class App {
// ...
constructor(controllers: any[]) {
// ...
this.initializeControllers(controllers);
this.initializeMiddleWares();
}
into this (notice the order of the lines):
class App {
// ...
constructor(controllers: any[]) {
// ...
this.initializeMiddleWares();
this.initializeControllers(controllers);
}
And you should be good to go.
I am trying to enable CORS to connect my nestJS API with a local react app. But it seems that CORS is blocking access from the React App.
I've tries this so far:
First attempt:
async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: true });
app.listen(3000);
}
bootstrap();
Second attempt:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
methods: ["GET", "POST"],
origin: '*',
})
app.listen(3000);
}
bootstrap();
And third attempt:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
methods: ["GET", "POST"],
origin: 'http://localhost:3001/',
})
app.listen(3000);
}
bootstrap();
Nothing of that seems to work.
The React app is just a simple superagent call like this:
const res = sa.get(`http://localhost:3000/jokes/random`).withCredentials().end(res => console.log(res))
I've tried to use the superagent with and without the withCredentials.
Any idea of what is going on? thank you.
I'm trying to authenticate through MSAL in my MERN app by clicking a button.
However I get this error :
Access to XMLHttpRequest at
'https://login.microsoftonline.com/common/oauth2/v2.0/a...'
(redirected from 'http://<SERVER_URL>/api/auth/signin') from origin
'http://<CLIENT_URL>' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
Here is the code of my NodeJS server :
const express = require("express");
const session = require('express-session');
const authRoutes = require("./routes/auth.routes");
const msal = require('#azure/msal-node');
const cors = require("cors");
require("dotenv").config();
const app = express();
const corsOptions = {
origin : process.env.CLIENT_URL,
credentials: true,
"allowedHeaders": ["sessionId", "Content-Type"],
"exposedHeaders": ["sessionId"],
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false
}
app.use(cors(corsOptions));
// Demo only
app.locals.users = {};
// MSAL Config
const msalConfig = {
auth: {
clientId: process.env.OAUTH_APP_ID,
authority: process.env.OAUTH_AUTHORITY,
clientSecret: process.env.OAUTH_APP_SECRET
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
app.locals.msalClient = new msal.ConfidentialClientApplication(msalConfig);
// Session middleware
app.use(session({
secret: 'your_secret_value_here',
resave: false,
saveUninitialized: false,
unset: 'destroy'
}));
app.use("/api/auth", authRoutes);
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(process.env.PORT, () => {
console.log(`Server is running on port ${process.env.PORT}`);
});
module.exports = app;
Here are my auth.controller methods :
module.exports = {
signIn: async (req, res) => {
const urlParameters = {
scopes: process.env.OAUTH_SCOPES.split(','),
redirectUri: process.env.OAUTH_REDIRECT_URI
};
try {
const authUrl = await req.app.locals.msalClient.getAuthCodeUrl(urlParameters);
res.redirect(authUrl);
} catch (error) {
console.log(`Error: ${error}`);
res.redirect("/");
}
},
callback: async (req, res) => {
const tokenRequest = {
code: req.query.code,
scopes: process.env.OAUTH_SCOPES.split(","),
redirectUri: process.env.OAUTH_REDIRECT_URI
};
try {
const response = await req.app.locals.msalClient.acquireTokenByCode(tokenRequest);
req.session.userId = response.account.homeAccountId;
const user = await graph.getUserDetails(response.accessToken);
req.app.locals.users[req.session.userId] = {
displayName: user.displayName,
email: user.mail || user.userPrincipalName,
timeZone: user.mailboxSettings.timeZone
};
} catch (error) {
console.log(`Error: ${error}`);
}
res.redirect("/");
},
signOut: async (req, res) => {
if (req.session.userId) {
const accounts = await req.app.locals.msalClient.getTokenCache().getAllAccounts();
const userAccount = accounts.find(a => a.homeAccountId === req.session.userId);
if (userAccount) {
req.app.locals.msalClient.getTokenCache().removeAccount(userAccount);
}
}
req.session.destroy(err => res.redirect("/"));
}
};
And here is the React part :
import React from 'react';
import axios from "axios";
const App = () => {
const handleConnect = () => {
axios({
method: "get",
url: `${process.env.SERVER_URL}/api/auth/signin`,
withCredentials: true
})
.then(res => console.log(res.data))
.catch(err => console.log(err));
};
return (
<button onClick={handleConnect}>Connect</button>
);
};
export default App;
In my Azure Active Directory admin center, my redirection URIs are :
"<CLIENT_URL>" as "SPA"
"<SERVER_URL>/api/auth/signin" as "Web"
The Network tab in devtools helps troubleshoot this sort of thing.
You probably need to handle CORS preflight requests, by putting something like this in your express app to handle OPTIONS requests.
app.options('*',cors())
Put this line before app.use() for any routes.
This one bit me in production. Ouch!
Setting Access-Control-Allow-Origin to * is very risky and not recommended. It means that you are allowing any origin to receive a response back from your server.
removing CORS means that Same Origin Policy will be enforced, therefor it won't work.
To solve the issue between your client and server, what you can do is set a proxy in your package.json file of the React app, which will point to your server: "proxy": "YourServerURI".
Regarding the initial question of the error from MSAL, I would suggest to double check that your app is registered correctly and has the permission to access your server.