I'm using express to make API calls to a e-commerce platform. The API uses sessions to handle the persistent data needed for user tasks, like account and cart records. Cart and account details are attached to sessions (and the cookies that the sessionID is stored in), so when I log in with User1 and create a cart with items, and then log out, the cart persists. However, when logging in with User2, they inherit the cart of User1 because it's attached to the session.
EDIT/UPDATE
Main app.js:
var nodemailer = require("nodemailer"),
request = require("superagent"),
flash = require("connect-flash"),
bodyParser = require("body-parser"),
session = require("express-session"),
cookieParser = require("cookie-parser"),
methodOverride = require("method-override"),
Schema = require("schema-client"),
express = require("express"),
nodeuuid = require("uuid"),
cors = require("cors"),
app = express();
app.use(session({
name: "X-Session",
secret: "randomstring",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 60*60*1000,
secure: false
}
}));
app.use(bodyParser.urlencoded({extended:false}))
.use(cookieParser())
.set("view engine", "ejs")
.use(express.static(__dirname + "/public"))
.use(methodOverride("_method"))
.use(flash())
var client = new Schema.Client("clientname", 'privateKeyhere');
var SchemaAPI = "https://clientname:privatekey#api.schema.io";
app.use(function(req, res, next){
res.locals.success = req.flash("success");
res.locals.errors = req.flash("error");
res.locals.account = req.session.account;
res.locals.session = req.session;
res.locals.cart = req.session.cart;
if(req.session.account_id){
client.get("/accounts/{id}", {
id: req.session.account_id
}, function(err, account){
if(account){
req.account = account;
res.locals.account = account;
};
next();
});
} else {
next();
}
});
Login Route:
app.post("/login", function(req, res, next) {
request
.post('http://localhost:3001/v1/account/login')
.set('X-Session', req.session.id)
.set('Accept', 'application/json')
.send({
email: req.body.email,
password: req.body.password
})
.end(function (error, account){
if(account){
account = account.body;
req.session.account = account;
console.log(account.name + " - " + account.id);
console.log(req.sessionID);
req.flash("success", "Logged in, " + account.email + ".");
res.redirect("/index");
} else if(account == null){
req.flash("error", "Your username or password is incorrect. Try again or <a href='/register'> sign up here</a>");
res.redirect("login");
} else {
console.log(error);
res.redirect('login');
}
});
});
All my other app routes have that "X-Session" header being passed with each request.
How can I create one session for each user such that when they log in, their session is retrieved, along with any cart information associated with their session? I'm using express-session to generate a sessionID, and then passing that ID to the API. Thanks in advance for your help.
Related
I'm using cookie storage session to hold user's token which is received from authentication. When I'm trying to set it after login and call it from the root.tsx's Loader Function, the userId is returned as undefined.
My loader function is:
export let loader: LoaderFunction = async({request, params}) => {
let userId = await getUserId(request);
console.log(userId);
return (userId ? userId : null);
}
The function which I receive the userId getUserId is defined as:
export async function getUserId(request: Request){
let session = await getUserSession(request);
let userId = session.get("userId");
if (!userId || typeof userId !== "string") return null;
return userId;
}
The getUserSession function is as:
export async function getUserSession(request: Request){
return getSession(request.headers.get('Cookie'));
}
I receive the getSession from destructring createCookieSessionStorage.
I'm creating a cookie with createUserSession function which is like:
export async function createUserSession(userId: string, redirectTo: string){
let session = await getSession();
session.set("userId", userId);
return redirect(redirectTo, {
headers: {
"Set-Cookie": await commitSession(session),
},
});
}
I also receive the commitSession from destructing createCookieSessionStorage. I used the same code from the Jokes demo app.
let { getSession, commitSession, destroySession } = createCookieSessionStorage({
cookie: {
name: "RJ_session",
secure: true,
secrets: [sessionSecret],
sameSite: "lax",
path: "/",
maxAge: 60 * 60 * 24 * 30,
httpOnly: true,
},
});
You configured the cookie to have secure: true, this makes the cookie only work with HTTPS, while some browsers allow secure cookies in localhost most don't do it so that may be causing your cookie to not be saved by the browser, making subsequent requests not receive the cookie at all.
Parse Cloud code:
Parse.Cloud.define("twitter", function(req, res) {
/*
|--------------------------------------------------------------------------
| Login with Twitter
| Note: Make sure "Request email addresses from users" is enabled
| under Permissions tab in your Twitter app. (https://apps.twitter.com)
|--------------------------------------------------------------------------
*/
var requestTokenUrl = 'htt****/oauth/request_token';
var accessTokenUrl = 'http***itter.com/oauth/access_token';
var profileUrl = 'https://api.twitter.com/1.1/account/verify_credentials.json';
// Part 1 of 2: Initial request from Satellizer.
if (!req.params.oauth_token || !req.params.oauth_verifier) {
var requestTokenOauth = {
consumer_key: 'EVJCRJfgcKSyNUQgOhr02aPC2',
consumer_secret: 'UsunEtBnEaQRMiq5yi4ijnjijnjijnijnjEjkjYzHNaaaSbQCe',
oauth_callback: req.params.redirectUri
};
// Step 1. Obtain request token for the authorization popup.
request.post({
url: requestTokenUrl,
oauth: requestTokenOauth
}, function(err, response, body) {
var oauthToken = qs.parse(body);
// console.log(body);
// Step 2. Send OAuth token back to open the authorization screen.
console.log(oauthToken);
res.success(oauthToken);
});
} else {
// Part 2 of 2: Second request after Authorize app is clicked.
var accessTokenOauth = {
consumer_key: 'EVJCRJfgcKSyNUQgOhr02aPC2',
consumer_secret: 'UsunEtBnEaQRMiq5yi4ijnjijnjijnijnjEjkjYzHNaaaSbQCe',
token: req.params.oauth_token,
verifier: req.params.oauth_verifier
};
// Step 3. Exchange oauth token and oauth verifier for access token.
request.post({
url: accessTokenUrl,
oauth: accessTokenOauth
}, function(err, response, accessToken) {
accessToken = qs.parse(accessToken);
var profileOauth = {
consumer_key: 'EVJCRJfgcKSyNUQgOhr02aPC2',
consumer_secret: 'UsunEtBnEaQRMiq5yi4ijnjijnjijnijnjEjkjYzHNaaaSbQCe',
token: accessToken.oauth_token,
token_secret: accessToken.oauth_token_secret,
};
console.log(profileOauth);
// Step 4. Retrieve user's profile information and email address.
request.get({
url: profileUrl,
qs: {
include_email: true
},
oauth: profileOauth,
json: true
}, function(err, response, profile, USER) {
console.log(profile);
//console.log(response.email);
Parse.Cloud.useMasterKey();
var UserPrivateInfo = Parse.Object.extend("UserPrivateInfo");
var query = new Parse.Query(UserPrivateInfo);
query.equalTo("email", profile.email);
query.first({
success: function(privateInfo) {
if (privateInfo) {
res.success(privateInfo.get('user'));
} else {
response.success();
}
},
error: function(error) {
response.error("Error : " + error.code + " : " + error.message);
}
});
});
});
}
});
For client side using Sendgrid twitter authentication:
loginCtrl.twitterLogin = function() {
$auth.authenticate("twitter").then(function(response) {
console.log(response.data.result);
var user = response.data.result;
if (!user.existed()) {
var promise = authFactory.saveUserStreamDetails(user, response.email);
promise.then(function(response) {
signInSuccess(response);
}, function(error) {
console.log("error while saving user details.");
});
} else {
signInSuccess(user);
}
}).catch(function(error) {
console.log(error);
});;
};
Issue:
Step 1: Called cloud function Parse.Cloud.define("twitter", function(req, res) using loginCtrl.twitterLogin
Step 2: Twitter popup opens and user logs in to twitter
Step 3: Got verification keys and again cloud function Parse.Cloud.define("twitter", function(req, res) is called and user is verified
Step 4: Got the user email using the twitter API.
Step 5: I can get the existing Parse User Object using the email or can signUp using that email.
Step 6: Returns the parse user object to client but there is no session attached to it so **How can I create user session?
Without parse session we can not log in to parse application. Every clound code api/ function call will fail as no session is attached to them. So how can I create and manage a session using twitter authentication.
I'm using parse on node. I have an express app, and a JS browser app, that is hosted off the express server.
At the moment the app has it's own login. It logs the user in on the client, and the client remains logged in.
I want to be able to log the client in via an express route /login. When they log in via this route, i want to log them in on the client side.
I have poured over documentation on this but I have struggled to find any real examples of how this is all done.
Here is some code i have found:
var cookieSession = require('cookie-session'),
// I added this require as it seems the code is using it;
session = require('express-session');
app.use(cookieSession({
name: COOKIE_NAME,
secret: "SECRET_SIGNING_KEY",
maxAge: 15724800000
}));
//
// This will add req.user if they are logged in;
//
app.use(function (req, res, next) {
Parse.Cloud.httpRequest({
url: 'http://localhost:1337/parse/users/me',
headers: {
'X-Parse-Application-Id': 'myAppId',
'X-Parse-REST-API-Key': 'myRestAPIKey',
'X-Parse-Session-Token': req.session.token
}
}).then(function (userData) {
req.user = Parse.Object.fromJSON(userData.data);
next();
}).then(null, function () {
return res.redirect('/login');
});
});
//
// login route;
//
app.post('/login', function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function(user) {
req.session.user = user;
req.session.token = user.getSessionToken();
res.redirect('/');
}, function(error) {
req.session = null;
res.render('login', { flash: error.message });
});
});
//
// and logout.
//
app.post('/logout', function(req, res) {
req.session = null;
res.redirect('/');
});
This looks pretty good, but this won't add a session on the client? How do parse the server login down to the client; Do i pass the session Token and use it on the client?
//
// If i call this code in the browser, i want the logged in user;
//
var current_user = Parse.User.current();
I have been unable to find any real code on-line that demonstrates all of this in the best-practice manner.
Is this the 'best practice' known solution or is there a better way of doing this?
When i use this function in Cloud Code Parse.User.current() return null.
I'm using parseExpressCookieSession for login.
Any advice?
var express = require('express');
var expressLayouts = require('cloud/express-layouts');
var parseExpressHttpsRedirect = require('parse-express-https-redirect');
var parseExpressCookieSession = require('parse-express-cookie-session');
// Required for initializing enter code hereExpress app in Cloud Code.
var app = express();
// Global app configuration section
app.set('views', 'cloud/views');
app.set('view engine', 'ejs'); // Switch to Jade by replacing ejs with jade here.
app.use(expressLayouts); // Use the layout engine for express
app.set('layout', 'layout');
app.use(parseExpressHttpsRedirect()); // Require user to be on HTTPS.
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('helloworld'));
app.use(parseExpressCookieSession({
fetchUser: true,
cookie: { maxAge: 3600000 * 24 }
}));
Parse.Cloud.beforeSave('Menu', function(request, response) {
var Business = Parse.Object.extend('Business');
var query = new Parse.Query(Business);
query.equalTo('profile', Parse.User.current().get('profile'));
query.find({
success: function(business) {
console.log(business);
response.success();
},
error: function(error) {
response.error(error.message);
}
});
});
app.listen();
This the code that i use to login/logout
app.post('/login', function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function(user) {
// Login succeeded, redirect to homepage.
// parseExpressCookieSession will automatically set cookie.
res.redirect('/');
},
function(error) {
// Login failed, redirect back to login form.
res.redirect('/');
});
});
// Logs out the user
app.post('/logout', function(req, res) {
Parse.User.logOut();
res.redirect('/');
});
It is an old question but answering for future reference.
Parse.User.current() works in Javascript SDK when used in clients ex. WebApp where users log in and the you can fetch the current user with that function.
To get the user calling a Cloud Code function or doing an operation on an object (beforeSave,afterSave,beforeDelete and so on) you use the request.user property it contains the user issuing the request to Parse.com.
More details about Parse.Cloud.FunctionRequest here: https://parse.com/docs/js/api/classes/Parse.Cloud.FunctionRequest.html
Example code:
Parse.Cloud.beforeSave('Menu', function(request, response) {
var requestUser = request.user;
// instance of Parse.User object of the user calling .save() on an object of class "Menu"
// code cut for brevity
});
I have modify https://github.com/jimpick/everyauth-example-password/blob/master/server.js for making login with mysql.
I want to access the session in
authenticate(function(login, password) {
var errors = [];
var user = [];
userModule.CheckUserLogin(login, password, function(err, results) {
if(results.length > 0) {
req.session.login = login;
return user;
}
else {
if(!user) return ['Login failed'];
}
});
return user;
})
I have this code in bottom
var app = express.createServer(
express.bodyParser()
, express.static(__dirname + "/public")
, express.cookieParser()
, express.session({ secret: 'htuayreve' })
, everyauth.middleware()
);
app.configure(function() {
app.set('view engine', 'jade');
});
app.get('/', function(req, res) {
res.render('home', { users: JSON.stringify(usersByLogin, null, 2) });
});
If I paste app code from bottom to top then everyayth's routing not worked.I want to simple know how I can access the req.session.login inside everyauth function.
You can't access the session from your authenticate function. The everyauth way of supporting access the authenticated user's information is for you to provide a findUserById function to everyauth that will look up a user record given the user's id that gets stored in the session during authentication. Once you do that you can access all the user's attributes in your route handlers via req.user.
See the 'Accessing the User' section on the everyauth website.