I'm building a web app with the MEAN Stack. What I am trying to achieve is that when the user logs in his user information get fetched by Angular from my REST API. I set up the API route http://localhost:3000/api/user/profile which should respond with json including the user object.
router.get('/user/profile', function(req, res, next){
//console.log(req);
if(req.user === undefined){
res.json({
success: false,
msg: 'Unautorized'
});
} else {
res.json({
success: true,
user: {
id: req.user.steam.id,
name: req.user.steam.name,
avatar: req.user.steam.avatar,
avatarmedium: req.user.steam.avatarmedium,
avatarfull: req.user.steam.avatarfull
}
});
}
});
When the user logs in Angular start a GET-Request:
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
console.log(profile);
},
err => {
console.log(err);
return false;
});
}
getProfile():
getProfile(){
return this.http.get('http://localhost:3000/api/user/profile')
.map(res => res.json());
}
When I load up my site, log in, and go to the profile page the returned object contains success: false and the message 'Unauthorized' instead of the user object. Why is this happening?
I completely redesigned my approach. I implemented json web token which now sends a token (containing all user data) to the user through a url parameter once he signs in.
Related
I am using signInWithCustomToken() after initiating it on the server.
async function signinWithToken(data, sendResponse) {
const { token } = data;
console.log(token);
signInWithCustomToken(auth, token)
.then((user) => {
console.log(user);
sendResponse({ success: true, user });
})
.catch((err) => {
sendResponse({ success: false, message: err.message
});
});
}
The problem is that the user object returned doesn't include the user details like displayName, email, etc...
Is there something I could do about it?
A custom token only contains the properties/claims that you put into it. Firebase doesn't add any information to the custom token, so if you find certain values missing, it's because your code didn't add them while minting the token.
Also see the Firebase documentation on minting a custom token using the Admin SDK.
The signInWithCustomToken() method returns a Promise which resolves with a UserCredential and not a User.
So you need to do as follows:
async function signinWithToken(data, sendResponse) {
const { token } = data;
console.log(token);
signInWithCustomToken(auth, token)
.then((userCredential) => {
console.log(userCredential.user);
//..
})
I am stuck in a bit of a dilemma here where once my user logs in I want to redirect them to the dashbord page but also send their json details to my client side javascript. I know that there can only be one res. send /end/json in a response and that I can send dynamic data using view engines.The reason why I want to send data separately is because I do not merely want to render it but rather use the data in my client side JS so that I can use it later for sockets in a chat application. I have tried a lot of things from using continuous local variables to try and create a middleware or an automatic redirect. The problem is no matter what the res.json() is hard to embed in a middleware as the very moment it is called there is no scope for declaring a next or redirect. Here is what my code looks like for the login route:
router.get(’/’, (req,res)=>{
console.log(req.user._id);
User.findOne({
"_id": req.user._id
}, function(err, foundUser) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundUser); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundUser
});
}
});
res.sendFile('chat.html', { root: path.join(__dirname, '../views/') });
});
you can make ajax request from your page to fetch the data you want and save it in your client side.
You need to make your chat.html page request the json data. This means you need two routes:
router.get(’/’, (req,res)=>{
es.sendFile('chat.html', { root: path.join(__dirname, '../views/') });
});
router.get(’/myself’, (req,res)=>{ // I normally call this route "myself"
// but you can call it anything you want
console.log(req.user._id);
User.findOne({
"_id": req.user._id
}, function(err, foundUser) {
if (err) {
console.log(err);
return res.status(500).json({
ok: false,
error: err
});
} else {
console.log(foundUser); //THE ELEMENT IS FOUND
return res.status(200).json({
ok: true,
data: foundUser
});
}
});
});
Now you need your chat.html file to make a request for the new /myself data. There are various ways to do this but for modern browsers you can use fetch:
chat.html
<html>
<head>
... rest of your html head
<script>
fetch('/myself')
.then(res => res.json())
.then(res => {
if (res.ok === false) {
// Handle your error here, I'm just alerting it:
alert(res.error);
}
else {
let user = res.data;
// Now you can do anything with the user data
// in here. I'm just logging it:
console.log('user =', user);
}
});
</script>
</head>
<body>
... rest of your html code
</body>
</html>
I have a login in my Angular 2 app, and I have been converting it from using a fake backend (which works) to connect to our mongoDB-based API instead.
This is the login function I am using in the authentication service:
login(username: string, password: string) {
const u = encodeURIComponent(username);
const p = encodeURIComponent(password);
this._url = `https://api.somesite.com/v0/staff/login/${u}/${p}?apikey=somekey`;
console.log(this._url);
return this.http.post(this._url, JSON.stringify({ username: username, password: password }))
.map((response: Response) => {
// login successful if there's a jwt token in the response
const user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
In my login component I am subscribing like this:
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.router.navigate(['/']);
console.log('User logged in as: ' + this.model.username);
},
error => {
this.alertService.error(error);
this.loading = false;
});
this.authenticationService.username = this.model.username;
}
When I try this, and log to the console "this_url", I get what I would expect. For instance, if the user typed in "billsmith" for username, and "parisnow" for password, I see this in the console for "this_url":
https://api.somesite.com/v0/staff/login/billsmith/parisnow?apikey=somekey
Furthermore, I can type that url directly into the browser address window and see data (when the username and password correctly correspond to actual records in our database). So it's accessing the correct info in that sense.
But in the console I get a "404" error for that generated url. It also doesn't "do anything". In other words, it doesn't correctly redirect to the main component as it did with the fakeBackend-enabled login. And the only thing that's different now is the url that I am calling (because I'm connecting to our actual API now, as opposed to a fake backend provider).
FYI, the url when using the fake backend looked like this:
return this.http.post('/api/authenticate', JSON.stringify({ username: username, password: password}))
What am I missing here?
By the way, this is how things look on the server side re: our mongoDB:
exports.byLogin = function(req, res, next) {
let ioOnly = false, username, password;
if (_.isUndefined(req.params)){
ioOnly=true;
username = req.username;
password = req.password;
}
else {
username = req.params.username;
password = req.params.password;
}
staff.findOne({username: username, password: password}, function(err, doc) {
if (err) { if (!ioOnly) { return next(err) } else { return res(err)}}
else if(doc) ((!ioOnly) ? res.send(doc) : res(doc));
else ((!ioOnly) ? res.sendStatus(204) : res(doc));
});
};
I am working on login functionality for my Angular 2 app. I've got it working with a MockMackend and fakeBackendProvider. Now I'm in the process of connecting to our actual API. I am running into an issue with that, though.
First off, let me show what I have that IS working by using the MockBackend and fakeBackendProvider.
This is my authentication service function:
login(username: string, password: string) {
return this.http.post('/api/authenticate', JSON.stringify({ username: username, password: password}))
.map((response: Response) => {
// login successful if there's a jwt token in the response
const user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
Again, then, in my login component, I am calling that function like this:
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.router.navigate(['/']);
console.log('User logged in as: ' + this.model.username);
},
error => {
this.alertService.error(error);
this.loading = false;
});
this.authenticationService.username = this.model.username;
}
Again, all of the above IS working.
So, I assume all I should need to do is replace '/api/authenticate' in the login function, with our actual api + api string. So this is what I've been trying:
login(username: string, password: string) {
return this.http.post('https://api.somesite.com&apikey=843c-4932-ckd33', JSON.stringify({ username: username, password: password}))
.map((response: Response) => {
// login successful if there's a jwt token in the response
const user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
This isn't working. In the console I get a "ERR_NAME_NOT_RESOLVED" error. Any ideas here?
I have a MongoDB/Webpack/NodeJS Express set up in my ReactJS + Redux project.
I am making API calls from action creators in redux, and reach the API server and get a successful status back, yet the data never gets saved and the database never gets created even checking with in terminal mongo -> dbs and it doesn't show practicedb database which I named it as.
What could be the issue? Am I missing something?
Any guidance or insight would be greatly appreciated. Thank you
This is my set up for API:
import axios from 'axios';
import { browserHistory } from 'react-router';
import cookie from 'react-cookie';
import { AUTH_USER, AUTH_ERROR } from './types';
const API_URL = 'http://localhost:3000/api';
export function errorHandler(dispatch, error, type) {
let errorMessage = (error.data.error) ? error.data.error : error.data;
// NOT AUTHENTICATED ERROR
if(error.status === 401) {
errorMessage = 'You are not authorized to do this.';
}
dispatch({
type: type,
payload: errorMessage
});
}
export function registerUser({ email }) {
return function(dispatch) {
axios.post(`${API_URL}/auth/register`, { email })
.then(response => {
console.log('THIS IS TESTING PURPOSE')
console.log(response)
dispatch({ type: AUTH_USER });
})
.catch((error) => {
errorHandler(dispatch, error.response, AUTH_ERROR)
});
}
}
And my API controller is set up as such:
"use strict";
const User = require('../models/user')
exports.register = function(req, res, next) {
const email = req.body.email;
console.log('ERROR 1')
if(!email) {
return res.status(422).send({ error: 'You must enter an email address.'})
console.log('ERROR 1')
}
User.findOne({ email: email }, function(err, existingUser) {
if(err) { return next(err); }
console.log('ERROR 2')
if(existingUser) {
return res.status(422).send({ error: 'That email address is already in use.'})
}
console.log('ERROR 3')
let user = new User({
email: email,
})
console.log('ERROR 4')
user.save(function(err, user) {
if(err) { return next(err); }
console.log('ERROR 5')
res.status(201).json({
user: user,
})
})
})
console.log('ERROR 6')
}
Configuration for the API:
module.exports = {
'database': 'mongodb://localhost/practicedb',
'port': process.env.PORT || 3000,
'secret': 'dogcat',
}
The project so far just has an input text field, where it accepts an email address. If the email has already been registered, the API should return the error That email address is already in use. and it does.
So I tried console logging to see what the problem is, and the first time I submit the POST request, it logs the following (the terminal showing API console logs):
And if I try to submit the same email again, it throws me the API error that the email is already in use with 422 error, yet the data do not get saved and database (practicedb) never get created:
Also, what is the OPTIONS request that shows up in terminal? I only made an attempt to POST. Lastly, is OPTIONS why the ERROR log in API server is not logging in chronological order?
EDIT
You're using the wrong Mongo shell command: db will only show you the current database (test), but if you want to see a list of all databases, you should use show dbs.
If you want to switch databases:
use practicedb
And, if you want to see the collections in the current database:
show collections