This question already has answers here:
How to store objects in HTML5 localStorage/sessionStorage
(24 answers)
Closed 11 months ago.
I am trying to login to my user account which is saved on database and attach a token to that username with 'jwt-token'.
router.post('/users/login', (req, res) => {
User.authenticate()(req.body.username, req.body.password, (err, user) => {
if (err) { console.log(err) }
res.json(user ? jwt.sign({ id: user._id }, process.env.SECRET) : null)
})
})
However when i login to the account, the token is being saved, as [Object][Object] in the local storage via this function here,
// when a user clicks login
const handleLogin = (event) => {
event.preventDefault();
axios.post('/api/users/login', {
username: userState.username,
password: userState.password
}).then(token => {
console.log(token)
setLoginState(true)
localStorage.setItem('username', userState.username)
localStorage.setItem('token', token)
}).catch(err => { console.log(err) })
What is the reason the token is saving as an object? is it not properly being created by my route? or am I not calling it correctly in my .then call? any insight would be appreciated. Still trying to learn as much as i can on backend work and seem to hit problems at every step.
We have to stringify while storing objects in storage and parse the stored objects while retrieving.
// Put the object into storage
localStorage.setItem('username', JSON.stringify(username));
// Retrieve the object from storage
var retrievedUsername= localStorage.getItem('username');
console.log('retrievedUsername: ', JSON.parse(retrievedUsername));
localStorage.setItem() saves information as Strings which is why you see "[Object][Object]" being saved since that is what it is receiving.
So you need to transform your object to a String before you save it.
You can achieve this by using the JSON.stringify() function.
Note: you will have to transform the String back to an object when you need to get it.
You can achieve this by using the JSON.parse()
Example:
localStorage.setItem('username', JSON.stringify(userState.username))
localStorage.setItem('token', JSON.stringify(token))
JSON.parse(localStorage.getItem('username'))
JSON.parse(localStorage.getItem('token'))
axios promise returns response object which has a data attribute. To access token you should call
res.data
and store it like so
localStorage.setItem('token',res.data)
Related
I'm learning express.js and I'm stuck on one little problem.
How can I save sessions in the browser so I don't have to log in every time. I use cookie-session. I send the login data downloaded from the form for validation using the POST method to endpoint ./login. After successfully passing the validation, it saves sessions in this way: req.session.admin = 1;, and then using redirect, it redirects to the admin endpoint. After redirecting to ./admin, I try to read if there is a previously saved req.session.admin session. The above action returns me undefined, and the req.session itself returns an empty object {}. I tried console.log on the ./login endpoint and yes, everything is OK i.e. it returns 1 and on the ./admin endpoint it is undfined.
My question to you is: Has anything changed recently in the implementation of cookie-session (although I don't think so, because I do it according to the documentation available on npm), or do I need to install some package besides cookie-session?
Save the session
.post('/login', (req, res) => {
const { body } = req;
if (password === body.password && login === body.login) {
req.session.admin = 1;
res.redirect('/admin');
} else {
res.redirect('/login');
}
});
This is where my problem arises, because the session is not saved and each time the validation fails, I return to login
.all('*', (req, res, next) => {
if (!req.session.admin) {
res.redirect('/login');
return;
}
next();
})
Firstly, req.session.admin = 1 does not save session, but it assigns value to separate request. Each request is independent.
You have to return some information to client (e.g token) for further using. Token should be sent in each request in appropriate header and express should verify it.
What's more you should not send credentials in plain text.
What I recommend is to familiarise yourself with JWT concept https://jwt.io/introduction
In my node.js express application I am retrieving a user from my database
const newUser = await User.create({
username,
password,
email,
avatar,
})
but before sending the response with the user object I want to remove the password.
delete newUser.password;
return res.status(200).json({ token, user: newUser });
but in my response the password is returned.
console.log(JSON.stringify(newUser))
returns:
{"_id":"11111111","username":"dylan","email":"dylan#email.com","admin":true,"password":"******"}
query return value is document not javascript object
Documents have a toObject method which converts the mongoose document into a plain JavaScript object.
first convert it to object and then use delete on each property you want
also with mongoose it can done more properly and automatically
User.methods.toJSON = function () {
const user = this;
const userObj = user.toObject();
delete userObj.password;
return userObj;
};
every time you send this document as response it convert to JSON and every time that JSON.strigify() is call on a document it call this toJSON() method
Maybe you can also do
delete newUser._doc.password
Below code is my fetch method in my separate register.js. This is my newly created js file, so I can create my front end. At the moment I'm just trying to console.log the ending result for this fetch, but can't get the output since I'm getting an error when I try to POST this.
error in browser console:
"Uncaught (in promise) SyntaxError: Unexpected token S in JSON at position 0"
fetch(`${rootUrl}api/users/register`,{
method:"POST",
headers:{
"Content-Type": "application/json"
},
body:JSON.stringify({
firstName: firstName,
lastName: lastName,
mobileNo: mobileNo,
email: email,
password: password
})
})
.then(result=>result.json())
.then(result =>{
console.log(result);
})
In userRouter.js, this is the route I'm fetching in register.js above:
router.post('/register', (req, res)=>{
userController.register(req.body).then(result => res.send(result))})
And the route leads to this controller in Usercontroller.js:
module.exports.register = (reqBody)=>{
//check if email already exists before registering new user
return User.find({email: reqBody.email}).then((result, error) =>{
if(result.length != 0){
return "EMAIL EXISTS!";
}else{
let newUser = new User({
firstName: reqBody.firstName,
lastName: reqBody.lastName,
email:reqBody.email,
password: bcrypt.hashSync(reqBody.password, 10),
mobileNo: reqBody.mobileNo
})
return newUser.save().then((result, error)=>{
if (error){
return error;
}else{
return "SUCCESFULLY REGISTERED NEW USER";
}
})
}
})}
As you can see, this is a registration form. Everything works fine in the backend, using postman to enter values. All my condition prompts are being returned(emails exist, successful registration).
But when I tried creating a frontend for it, I can't get my defined prompts.Like when I deliberately input a duplicate email, I can't get the message "Email exists" that I used to get when using only postman or just backend API functionality.
I feel like something is very wrong with what I'm trying to do. I'm having trouble creating a frontend for my API which I'm not used at the moment.
You are returning a non JSON response, so you can't use res.json(). You are simply sending a text response. So use res.text()
fetch('/your-endpoint').then((res)=>{
return res.text();
}).then((text)=>{
console.log(text)
})
There are some hints to be pointed out.
Check the rootUrl since after that there's no foreslash.
You're sending back the Text Style. use this instead to have the result json format.
res.status(200).json({result})
Try not to use Synchronous Functionalities on the back side. You
should give it a wide berth, or rather, use bcrypt.hash() mixed
with Async Function to remove the CallBack Function until it gets
done. What's more, so as to check the previous function's error to
get it on the front side using Fetch / Axios. use Try/Catch method.
I'd use axios [ axios.request({}) | axios.post(..)] if I were in
your shoes.
Im using the firebase authentication function which returns a user object as follows:
auth()
.createUserWithEmailAndPassword(email, password)
.then(user => {
Im then trying to save this user object to the Firebase database like so
database()
.ref('profiles/users/' + user.user.uid)
.set({
myUserObj: user,
})
However firebase database is returning an error 'Cannot read property 'code' of undefined' FULL CODE BELOW
auth()
.createUserWithEmailAndPassword(email, password)
.then(user => {
console.log(user.user);
database()
.ref('profiles/users/' + user.user.uid)
.set({
myUserObj: user,
})
.catch(err =>
console.log(err.message),
);
})
Firebase Realtime Database can only store valid JSON objects. The UserCredential object contains many methods, which makes it not a valid JSON object.
You could give it a try to save it with:
database()
.ref('profiles/users/' + user.user.uid)
.set({
myUserObj: JSON.parse(JSON.stringify(user)),
})
If this doesn't work, you'll have to explicitly name the properties that you want to save.
I'm authenticating users with google/facebook/ms Oauth and I'm then giving them a refresh token. I then use this long-lived refresh token to make requests for short-lived access tokens.
The issue I'm having is my app uses the social profile's photo to display on the frontend but the URL will stop working after the social token expired.
I'm trying to save the user's profile photo to MSSQL DB as varbinary(max) and then serve it back to the front-end with the access tokens.
Here's my code so far around this:
But I'm not sure how to get a binary from the buffer instead of the base64 string?
request.get(
{ url: req.user._json.picture, encoding: null },
function(err, res, buffer) {
res.on('close', () => {
theRes.send(buffer.toString('base64'));
return buffer.toString('base64');
knex('USERS')
.update({ photo: photo })
.where({ id: req.user.dbUserID })
.then(() => {
console.log('PHOTO UPDATED');
console.log(res);
console.log(photo);
})
.catch(err => {
console.log('ERROR ADDING PHOTO TO DATABASE');
console.log(err);
});
});
});
}
);
EDIT: This is not the same as how to return response from async call, I know how to do that and I'm already doing it in the code example, why on earth would you mark this as a duplicate of that???
It can just be stored as a base64 string as it's easier to handle but in the end I just took the dive and implemented blob storage as it's never a good idea to hog a production database with storing actual files in it.