Cookies not showing up - reactjs

I am having trouble getting my express server to attach a cookie on login. Bellow is the code I have written, I recently deployed my react app on Vercel which is what is making requests to my express server which I am still running locally. Everything works as it should and cookies are attaches when I run the react app locally.
Thank you,
Express Server
router.post("/", (req, res) =>{
const email = req.body.userName.toLowerCase()
const pass = req.body.password
db.query(`SELECT * FROM users WHERE email = '${email}'`, async (err, result) => {
if(result.rows.length === 1){
let user = result.rows[0]
bcrypt.compare(pass, user.password, (err, result) => {
if (err) throw err;
if(result === true){
user.password = 'blocked'
let token = jwt.sign({"tokenInfo": user, "userType": user.user_type}, secret, { algorithm: 'HS256'})
return res.cookie('userId', token, {
maxAge: 60000 * 60 * 2,
httpOnly: false
}).send({'message': "User Loged In", 'userType': user.user_type, 'userID': user.apaid})
} else {
return res.send({'message': 'Invalid Password', 'userType': 'false'})
}
})
} else if(result.rows.length > 1) {
res.send('WTF')
} else {
res.send({'message': 'Invalid User Name', 'userType': 'false'})
}
console.log(res.cookies)
})
})

Frontend and backend parts of your app should be served on the same domain in order to use cookies. If you created your app with create-react-app you can set up a proxy in your package.json file of your react app.
"devDependencies": {
...
},
"proxy": "http://*address of your locally running server eg:localhost:5000/*"

Related

Amplify Admin Queries API addUserToGroup giving 403 with "User does not have permissions to perform administrative tasks" message

I am working on React + Amplify app and have implemented custom authentication. For Authorization, I have created different user groups in Cognito.
Once the user confirms the sign up process, I want to add him/her to a specific Cognito user pool group named 'applicant'. I have created this group and running the following code on Sign up:
const confirmRegister = async (e) => {
try {
e.preventDefault();
await Auth.confirmSignUp(user.email, user.authenticationCode);
console.log("User Signed up Successfully.");
addToGroup(user.email, "applicant");
navigate("/dashboard");
} catch (error) {
console.log("error confirming sign up", error);
}
};
const addToGroup = async (userEmail, groupName) => {
let apiName = "AdminQueries";
let path = "/addUserToGroup";
let myInit = {
body: {
username: userEmail,
groupname: groupName,
},
headers: {
"Content-Type": "application/json",
Authorization: `${(await Auth.currentSession())
.getAccessToken()
.getJwtToken()}`,
},
};
await API.post(apiName, path, myInit);
console.log(`${userEmail} added to the group ${groupName}`);
};
The user is signing up successfully with this but not adding to the Cognito group, giving me 403 "Request failed with status code 403". The network tab shows this:
message: "User does not have permissions to perform administrative tasks"
I have used the CLI to restrict API access to this particular group as well but not working. Please let me know how to resolve this. Thanks in advance.

Shopify - App must set security headers to protect against clickjacking

I'm new to Shopify and I'm trying to help a friend with their website. I'm getting the following errors at the moment.
1. App must set security headers to protect against clickjacking.
Your app does not request installation on the shop immediately after clicking "add app". Apps must ask a shop for access when being installed on a shop for the first time, as well as when they are being reinstalled after having been removed. During install or reinstall we expected OAuth to be initiated at https://cambridgetestshop.myshopify.com/admin/oauth/request_grant but was redirected to https://app-staging.hashgifted.com/. Learn more about authentication in our developer documentation
2. App must verify the authenticity of the request from Shopify.
Your app does not request installation on the shop immediately after clicking "add app". Apps must ask a shop for access when being installed on a shop for the first time, as well as when they are being reinstalled after having been removed. During install or reinstall we expected OAuth to be initiated at https://cambridgetestshop.myshopify.com/admin/oauth/request_grant but was redirected to https://app-staging.hashgifted.com/. Learn more about authentication in our developer documentation
We're using React built in Yarn. I'm not sure about next steps, thanks!
it seems that you're not following the documentation in regarding of authentication and app installation process.
As you're using node I suggest you to take a look at this project https://github.com/Shopify/shopify-app-node
and in particular to the authentication middleware, this is one part
import { Shopify } from "#shopify/shopify-api";
import topLevelAuthRedirect from "../helpers/top-level-auth-redirect.js";
export default function applyAuthMiddleware(app) {
app.get("/auth", async (req, res) => {
if (!req.signedCookies[app.get("top-level-oauth-cookie")]) {
return res.redirect(
`/auth/toplevel?${new URLSearchParams(req.query).toString()}`
);
}
const redirectUrl = await Shopify.Auth.beginAuth(
req,
res,
req.query.shop,
"/auth/callback",
app.get("use-online-tokens")
);
res.redirect(redirectUrl);
});
app.get("/auth/toplevel", (req, res) => {
res.cookie(app.get("top-level-oauth-cookie"), "1", {
signed: true,
httpOnly: true,
sameSite: "strict",
});
res.set("Content-Type", "text/html");
res.send(
topLevelAuthRedirect({
apiKey: Shopify.Context.API_KEY,
hostName: Shopify.Context.HOST_NAME,
host: req.query.host,
query: req.query,
})
);
});
app.get("/auth/callback", async (req, res) => {
try {
const session = await Shopify.Auth.validateAuthCallback(
req,
res,
req.query
);
const host = req.query.host;
app.set(
"active-shopify-shops",
Object.assign(app.get("active-shopify-shops"), {
[session.shop]: session.scope,
})
);
const response = await Shopify.Webhooks.Registry.register({
shop: session.shop,
accessToken: session.accessToken,
topic: "APP_UNINSTALLED",
path: "/webhooks",
});
if (!response["APP_UNINSTALLED"].success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
res.redirect(`/?shop=${session.shop}&host=${host}`);
} catch (e) {
switch (true) {
case e instanceof Shopify.Errors.InvalidOAuthError:
res.status(400);
res.send(e.message);
break;
case e instanceof Shopify.Errors.CookieNotFound:
case e instanceof Shopify.Errors.SessionNotFound:
// This is likely because the OAuth session cookie expired before the merchant approved the request
res.redirect(`/auth?shop=${req.query.shop}`);
break;
default:
res.status(500);
res.send(e.message);
break;
}
}
});
}

MERN stack with https connection is unable to set cookies on Chrome but sets them on all other browsers

I am developing a typical MERN application and I've completed the authentication cycle. My NodeJS/Express back-end uses 'express-session' and 'connect-mongodb-connection' to create and handle sessions. The React front-end uses 'axios' for communicating with the API. The authentication cycle works on all browsers except Chrome. For all other browsers, a session is successfully created in MongoDB, cookies are set in the browser and I am successfully logged into a session.
But when testing this with Chrome, everything works perfectly except for the part where cookies are set. I've tested this rigorously over the span of a day and I can trace the cookie to the point where it's sent from the back-end. But Chrome refuses to save the cookie.
Here is my code for maintaining sessions:
server/app.js
var store = new MongoDBStore({
uri: DB,
collection: 'sessions'
});
// Catch errors
store.on('error', function (error) {
console.log(error);
});
app.use(require('express-session')({
secret: process.env.SESSION_SECRET,
saveUninitialized: false, // don't create session until something stored
resave: false, //don't save session if unmodified
store: store,
cookie: {
maxAge: parseInt(process.env.SESSION_LIFETIME), // 1 week
httpOnly: true,
secure: !(process.env.NODE_ENV === "development"),
sameSite: false
},
}));
//Mongo Session Logic End
app.enable('trust proxy');
// 1) GLOBAL MIDDLEWARES
// Implement CORS
app.use(cors({
origin: [
process.env.CLIENT_ORIGINS.split(',')
],
credentials: true,
exposedHeaders: ['set-cookie']
}));
The CLIENT_ORIGINS are set to the https://localhost:3000 and http://localhost:3000 where my React client runs.
Some things I've tried:
Trying all combinations of secure:true & secure:false with all combinations of sameSite:false & sameSite:'strict'
Setting domain to NULL or empty string
Trying to change path randomly
Here's my code for setting the cookies on login at the back-end:
exports.signIn = async (req, res, next) => {
const { email, password } = req.body;
if (signedIn(req)) {
res.status(406).json('Already Signed In');
return;
}
const user = await User.findOne({ email: email });
if (!user) {
res.status(400).json('Please enter a correct email.');
return;
}
if (!(await user.matchPassword(password))) {
res.status(400).json('Please enter a correct password.');
return;
}
req.session.userId = user.id;
res.status(200).json({ msg: 'Signed In', user: user });
};
This is the generic request model I use for calling my API from React using Axios:
import axios from "axios";
import CONFIG from "../Services/Config";
axios.defaults.withCredentials = true;
const SERVER = CONFIG.SERVER + "/api";
let request = (method, extension, data = null, responseTypeFile = false) => {
//setting up headers
let config = {
headers: {
"Content-Type": "application/json",
},
};
// let token = localStorage["token"];
// if (token) {
// config.headers["Authorization"] = `Bearer ${token}`;
// }
//POST Requests
if (method === "post") {
// if (responseTypeFile) {
// config['responseType'] = 'blob'
// }
// console.log('request received file')
// console.log(data)
return axios.post(`${SERVER}/${extension}`, data, config);
}
//PUT Requests
else if (method === "put") {
return axios.put(`${SERVER}/${extension}`, data, config);
}
//GET Requests
else if (method === "get") {
if (data != null) {
return axios.get(`${SERVER}/${extension}/${data}`, config);
} else {
return axios.get(`${SERVER}/${extension}`, config);
}
}
//DELETE Requests
else if (method === "delete") {
if (data != null) {
return axios.delete(`${SERVER}/${extension}/${data}`, config);
} else {
return axios.delete(`${SERVER}/${extension}`, config);
}
}
};
export default request;
Some more things that I have tested:
I have double checked that credentials are set to true on both sides.
I have made sure that the authentication cycle is working on other browsers.
I have also made sure that the authentication cycle works on Chrome when I run React on http instead of https
I have also added my self signed certificate into the trusted root certificates on my local machine. Chrome no longer shows me a warning but still refuses to save cookies
I have made sure that the authentication cycle works if I run an instance of Chrome with web security disabled.
I've tried to make it work by using 127.0.0.1 instead of localhost in the address bar to no avail.
No errors are logged on either side's console.
Any and all help would be appreciated
Chrome is always doing crazy stuff with cookies and localStorage...
It seems since chrome 80 chrome will reject any cookies that hasn't specifically set SameSite=None and Secure while using cross site requests. That issue, https://github.com/google/google-api-javascript-client/issues/561, is still open and being discussed there. I also think that using https while not setting Secure will also have it be rejected.
I have faced this same issue once and I have solved it by specifically set mentioned below:
document.cookie = "access_token=" + "<YOUR TOKEN>" + ";path=/;domain=."+ "<YOUR DOMAIN NAME>" +".com;secure;sameSite=none";
Make sure:
Your Path variable is set to /.
Your Domain is set to .<YOUR DOMAIN NAME>.com (NOTE: Here . dots is necessary part).
Your secure variable should be true.
Your sameSite variable should be none.
So I figured out the solution to my issue. My client-side was running on an https connection (even during development), because the nature of my project required so.
After much research, I was sure that the settings to be used for express-session were these:
app.use(require('express-session')({
secret: process.env.SESSION_SECRET,
saveUninitialized: false, // don't create session until something stored
resave: false, //don't save session if unmodified
store: store,
cookie: {
maxAge: parseInt(process.env.SESSION_LIFETIME), // 1 week
httpOnly: true,
secure: true,
sameSite: "none"
},
}));
Keep in mind that my client-side is running on an https connection even in development. However, despite using these settings, my login cycle did not work on Chrome and my cookies weren't being set.
Express session refused to send back cookies to the client, because despite having my client run on an https connection, it contacted my server on an http connection (my server was still running on an http connection in development), hence making the connection insecure.
So I added the following code to my server:
const https = require('https');
const fs = require('fs');
var key = fs.readFileSync("./certificates/localhost.key");
var cert = fs.readFileSync("./certificates/localhost.crt");
var credentials = {
key,
cert
};
const app = express();
const port = process.env.PORT || 3080;
const server = process.env.NODE_ENV === 'development' ? https.createServer(credentials, app) : app;
server.listen(port, () => {
console.log(`App running on port ${port}...`);
});
I used a self-signed certificate to run my server on an https connection during development. This along with sameSite: "none" and secure: true resolve the issue on Chrome (and all other browsers).

Office UI Outlook addin using auth is unstable

We're currently developing a Office UI addin using React. The addin should make a connection with a backend api and authenticate the user using bearer tokens. The backend api is protected by Azure AD.
We based our solution on the example that is offered by Microsoft: https://github.com/OfficeDev/PnP-OfficeAddins/tree/master/Samples/auth/Office-Add-in-Microsoft-Graph-React This uses msal.js for the authentication.
The login dialog is opened like so:
await Office.context.ui.displayDialogAsync(dialogLoginUrl, { height: 40, width: 30 }, result => {
if (result.status === Office.AsyncResultStatus.Failed) {
displayError(`${result.error.code} ${result.error.message}`);
} else {
loginDialog = result.value;
loginDialog.addEventHandler(Office.EventType.DialogMessageReceived, processLoginMessage);
loginDialog.addEventHandler(Office.EventType.DialogEventReceived, processLoginDialogEvent);
}
});
And the following code runs within the dialog:
import { UserAgentApplication } from "msal";
(() => {
// The initialize function must be run each time a new page is loaded
Office.initialize = () => {
const config = {
auth: {
clientId: "",
authority: "",
redirectUri: "https://localhost:3000/login.html",
navigateToLoginRequestUrl: false
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: false
}
};
const userAgentApp = new UserAgentApplication(config);
const authCallback = (error, response) => {
if (!error) {
if (response.tokenType === "id_token") {
localStorage.setItem("loggedIn", "yes");
} else {
// The tokenType is access_token, so send success message and token.
Office.context.ui.messageParent(JSON.stringify({ status: "success", result: response.accessToken }));
}
} else {
const errorData = `errorCode: ${error.errorCode}
message: ${error.errorMessage}
errorStack: ${error.stack}`;
Office.context.ui.messageParent(JSON.stringify({ status: "failure", result: errorData }));
}
};
userAgentApp.handleRedirectCallback(authCallback);
const request = {
scopes: ["api://..."]
};
if (localStorage.getItem("loggedIn") === "yes") {
userAgentApp.acquireTokenRedirect(request);
} else {
// This will login the user and then the (response.tokenType === "id_token")
// path in authCallback below will run, which sets localStorage.loggedIn to "yes"
// and then the dialog is redirected back to this script, so the
// acquireTokenRedirect above runs.
userAgentApp.loginRedirect(request);
}
};
})();
Unfortunately this doesn't seem lead to a stable addin. The authentication dialog sometimes works as expected, but sometimes it doesn't. In Outlook on macOS it seems to work fine, but in Outlook on Windows the handling of the callback is not always working correctly. Also in the web version of Outlook it doesn't work as expected.
The question is whether someone has a working solution using React and msal.js in a Outlook addin.

Amplify - GraphQL request headers are empty

I am attempting to create an app that utilizes Cognito user pools for user auth and then sending api requests to a dynamoDB table through graphQL.
The user auth/signup works correctly, however I receive a 401 error when attempting to query a data table. The message states "Missing authorization header"
I saw in a similar post that the auth token should be auto-populated into the request headers, but that does not occur for me. I also saw that Amplify created a function for custom graphql headers. I attempted this also but still get the same "Missing authorization header" error.
Any suggestions?
aws_appsync_graphqlEndpoint:'',
aws_appsync_region:'',
aws_appsync_authenticationType:'AMAZON_COGNITO_USER_POOLS',
graphql_headers: async () => ({
'My-Custom-Header': cognitoUser
})
}
This is in my config/exports file for amplify ---- Amplify.configure(config)
if (cognitoUser != null) {
cognitoUser.getSession((err, session) => {
if (err) {
console.log(err);
} else if (!session.isValid()) {
console.log("Invalid session.");
} else {
console.log( session.getIdToken().getJwtToken());
}
});
} else {
console.log("User not found.");
}
console.log(cognitoUser)
Amplify.configure(config)
const client = new AWSAppSyncClient({
disableOffline: true,
url: config.aws_appsync_graphqlEndpoint,
region: config.aws_appsync_region,
identityPoolId: config.aws_cognito_identity_pool_id,
userPoolId: config.aws_user_pools_id,
userPoolWebClientId: config.ws_user_pools_web_client_id,
auth: {
type: config.aws_appsync_authenticationType,
jwtoken: async () =>
(await Auth.currentSession()).getIdToken().getJwtToken(),
apiKey: config.aws_appsync_apiKey
}
});```
This is my client settings in my index.js folder
I apologize if I missed something blatant. I am new to backend and am having trouble with getting this to work.
I have only gotten it to work when using API_Key auth.

Resources