Showing error message on MEAN website - angularjs

I am quite new to MEAN and I am learning a lot. At the moment I am trying to show an error message on my page when an user is not allowed into the website. The page contains a button which redirects you to the steam login. After you login the steam API sends your steamid which I will then check in the mongodb database:
app.get('/auth/steam/return',
passport.authenticate('steam', { failureRedirect: '/' }),https://stackoverflow.com/users/5333805/luud-van-keulen
function(req, res) {
UserModel.findOne({ steamid : req.user.id }, function (err, user) {
if(!user) {
console.log('does not exist');
//Probably have to set the error message here
} else {
req.session.userid = req.user.id; //Setting the session
}
});
res.redirect('/');
});
The only thing that I can't get working is how to show a message when the user is not allowed (he is not in the database). I want to use AngularJS for the HTML (so no Jade).
I do know that I have to set a variable somewhere in the response header and then with AngularJS I need to check if this variable exists or not. When It exist it should show the div which contains the error message.
The problem is that I can't use res.render because I need to redirect.

So in the block where user is not found, you should have something like:
res.status(401).send("Login failed.");
And then on the client side you can check the response status and display the mesage.
Edit: if you need help on the client side as well, please provide your client code.

I ended up using express-flash.

Related

React component only displays status code error message instead of custom ones

During POST to register new user I check if that user already exists in mongoDB data base and if yes display this in react near the register form. I'm using express.js to create my API and axios to send requests from client side. This is how I check if user is registered.
const user = await Model.User.findOne({email: req.body.email});
if(user) return res.status(400).send('User already registered');
This is the function that is being called on Register button click:
handleSubmit= async (userData) =>{
await apis.registerNewUser(userData)
.then(res => console.log(res.body))
.catch(err => {
console.log(err);
this.setState({errorMessage: err.message});
})
}
The problem is that I can't display the custom error message that I add when sending response. Instead of getting "User already registered" I get "400 Bad request" showing near my register form. When I post through postman there is no problem, the response "User already registered" shows up in the response text window however that part doesnt exist when recieving error on react side. I can't send user an error that tells him nothing about the reason why he can't register. How can I get "User already registered" in react?
I have found the solution. In order to read the property of that custom text put inside send() when catching error I need to read from err.response.data - that's the right property to read "User already registered".I hope it helps someone one day.

I am trying to add firebase email varification link varification to my app but getting error "can not read email propperty of null"

I am trying to add firebase email verification link verification to my app but getting an error cannot read email property of null
I tried to follow the firebase docs for the web but not able to find the complete solution exactly where and how to implement it
var actionCodeSettings = {
url: 'campatron.com' + firebase.auth().currentUser.email,
handleCodeInApp: true,
// When multiple custom dynamic link domains are defined, specify which
// one to use.
dynamicLinkDomain: "example.page.link"
};
firebase.auth().currentUser.sendEmailVerification(actionCodeSettings)
.then(function() {
// Verification email sent.
})
.catch(function(error) {
// Error occurred. Inspect error.code.
});
The currentUser property is not yet initialized, meaning that your user is not yet logged in when you reach this code. Where is this piece of code called in your app?

auto-login user when reopening app in Backand

I have a simple Backand and Ionic app where I want users to log in once and no more from that point on, just like the Facebook app for example.
So once the user is logged in, I receive a token from Backand. From what I know, I assume I have to save that token in localStorage (which I'm doing, and works). But from that point on, I don't understand what I need to do to log the user back in when he revisits.
I have tried in my angular "run" method to look for an existing token in the localstorage, and if one exists, I paste it in my http headers. (the following function exists in the authentication service and is being called in the "run" method).
self.checkExistingUser = function() {
if ($localStorage.user_token) {
$http.defaults.headers.common.Authorization = $localStorage.user_token;
Backand.user.getUserDetails()
.then(function (response) {
// Do stuff
}
console.log('Token found, logging in user');
}
};
I assumed that the "getUserDetails()" call would interpret the Authorization header I had just added. But that's what I misunderstood; that's not how it works.
So my question is: how do I automatically log in the returning (existing) user with that token? I can't seem to find any function for that purpose in the Backand docs.
Thanks in advance!
Using Backend Vanilla SDK, this code:
backand.user.getUserDetails(false)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
will get the user details if he is authenticated, or null if not.
So you do not need to login the user again. The false makes sure that it checks it internally without contacting Backend. You should structure your app around it.
Your comment made me find the answer to my question, Kornatzky.
The problem was that I had included my appName, anonymousToken and signUpToken into the initialization (BackandProvider.init). Removing the anonymousToken and adding useAnonymousTokenByDefault:false solved the problem.
getUserDetails now returns my currently logged-in user instead of a Guest object. Thanks for your help!

How do I send user specific data with socket.io and laravel?

I am not sure how to word this question right, but here I go. I have laravel, angular, node w/socket.io and I am also using JWT for authentication. My end goal is to be able to send real time update notifications to specific users. For the life of me, I cannot seem to get how the workflow would be.
My initial though was to send the jwt within the handshake and then use then in node to do http requests to get data, and then return said data. In another words, when a specific event is fired, node will already have the token, send request to laravel for specific information.
Can someone please explain to me how sending user specific data via socket.io in this architecture?
I found this great article : https://www.ukietech.com/blog/programming/step-by-step-instruction-of-setting-up-real-time-secure-broadcasting-with-laravel-5-1-socket-io-and-redis/
This set me on the right track.
First I need to pass in my JWT into the socket:
var socket = io('http://192.168.10.10:3000', {query: "Authorization="+$rootScope.$storage.satellizer_token});
Next I actually verify the token.. again. I know this may be overkill, but I want to know that what hits the socket is legit.
io.use(function(socket, next){
if (socket.handshake.query.Authorization) {
var config = {
url:'http://192.168.10.10/api/auth',
headers:{
Authorization:'Bearer '+socket.handshake.query.Authorization
}
};
request.get(config,function(error,response,body){
socket.userId = JSON.parse(body).id;
next();
});
}
// call next() with an Error if you need to reject the connection.
next(new Error('Authentication error'));
});
The request in this block of code returns a user object based on the authenticated token. Refer to JWTAuth for more.
Then on connection I will assign the user to a unique channel.
io.on('connection',function(socket){
socket.join('userNotifications.'+socket.userId);
console.log('user joined room: userNotifications.'+socket.userId);
});
Then broadcast the event:
notifications.on('pmessage', function(subscribed, channel, message) {
var m = JSON.parse(message);
io.emit(channel+":"+m.event, message);
});
Back on the client side I listen for the channel. the var user is the user id.
socket.on('userNotifications.'+ user+':App\\Events\\notifications', function(message){
console.log(message);
});

Basic Authentication in CakePHP

I am trying to setup Basic Authentication for my CakePHP app so I can use it as an API for an upcoming mobile application. However If I pass the following:
cameron:password#dev.driz.co.uk/basic/locked/
Where cameron is the username, password is the password, and the rest is the domain and application. locked is a method that requires authentication. (obviously the password is wrong in this example)
(Q1) I will be requested for a username and password in a prompt... but the username and password are in fact correct as if I then type them into the prompt they work... Why would this happen? Haven't I just passed the username and password?
I can't see anything wrong with the way I have set this up in CakePHP.
I set Basic Auth in AppController as:
public $components = array('Auth');
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->authorize = array('Controller');
$this->Auth->authenticate = array('Basic');
$this->Auth->sessionKey = false;
$this->Auth->unauthorizedRedirect = false;
}
(Q2) Even so I have set both sessions to be false and the redirect to false, if the user cancels the prompt then they are redirected to the login page? Any ideas on how to stop this from happening? Ideally I want to send back a JSON response or status code of 401 (depending if it's an AJAX request or not).
So something like:
if ($this->request->is('ajax')) {
$response = json_encode(
array(
'meta'=>array(
'code'=>$this->response->statusCode(401),
'in'=>round(microtime(true) - TIME_START, 4)
),
'response'=>array(
'status'=>'error',
'message'=>'401 Not Authorized'
)
)
);
// Handle JSONP
if(isset($_GET['callback'])) {
$response = $_GET['callback'] . '(' . $response . ')';
}
// Return JSON
$this->autoRender = false;
$this->response->type('json');
$this->response->body($response);
} else {
header('HTTP/1.0 401 Unauthorized');
}
But where would this go in the application logic to show this? It needs to happen for ALL requested methods that require authentication and user fails or cancels the authentication.
(Q3) If you enter incorrect details you are just shown the prompt again until you get the username/password correct or hit cancel. How can I make it show an error?
Any ideas for these three issues (marked as sub questions numbers).
Update: This is how I send the headers to the API:
"use strict";jQuery.base64=(function($){var _PADCHAR="=",_ALPHA="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",_VERSION="1.0";function _getbyte64(s,i){var idx=_ALPHA.indexOf(s.charAt(i));if(idx===-1){throw"Cannot decode base64"}return idx}function _decode(s){var pads=0,i,b10,imax=s.length,x=[];s=String(s);if(imax===0){return s}if(imax%4!==0){throw"Cannot decode base64"}if(s.charAt(imax-1)===_PADCHAR){pads=1;if(s.charAt(imax-2)===_PADCHAR){pads=2}imax-=4}for(i=0;i<imax;i+=4){b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i+1)<<12)|(_getbyte64(s,i+2)<<6)|_getbyte64(s,i+3);x.push(String.fromCharCode(b10>>16,(b10>>8)&255,b10&255))}switch(pads){case 1:b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i+1)<<12)|(_getbyte64(s,i+2)<<6);x.push(String.fromCharCode(b10>>16,(b10>>8)&255));break;case 2:b10=(_getbyte64(s,i)<<18)|(_getbyte64(s,i+1)<<12);x.push(String.fromCharCode(b10>>16));break}return x.join("")}function _getbyte(s,i){var x=s.charCodeAt(i);if(x>255){throw"INVALID_CHARACTER_ERR: DOM Exception 5"}return x}function _encode(s){if(arguments.length!==1){throw"SyntaxError: exactly one argument required"}s=String(s);var i,b10,x=[],imax=s.length-s.length%3;if(s.length===0){return s}for(i=0;i<imax;i+=3){b10=(_getbyte(s,i)<<16)|(_getbyte(s,i+1)<<8)|_getbyte(s,i+2);x.push(_ALPHA.charAt(b10>>18));x.push(_ALPHA.charAt((b10>>12)&63));x.push(_ALPHA.charAt((b10>>6)&63));x.push(_ALPHA.charAt(b10&63))}switch(s.length-imax){case 1:b10=_getbyte(s,i)<<16;x.push(_ALPHA.charAt(b10>>18)+_ALPHA.charAt((b10>>12)&63)+_PADCHAR+_PADCHAR);break;case 2:b10=(_getbyte(s,i)<<16)|(_getbyte(s,i+1)<<8);x.push(_ALPHA.charAt(b10>>18)+_ALPHA.charAt((b10>>12)&63)+_ALPHA.charAt((b10>>6)&63)+_PADCHAR);break}return x.join("")}return{decode:_decode,encode:_encode,VERSION:_VERSION}}(jQuery));
$(document).ready(function(){
var username = 'cameron';
var password = 'password';
$.ajax({
type: 'GET',
url: 'http://dev.driz.co.uk/basic/locked',
beforeSend : function(xhr) {
var base64 = $.base64.encode(username + ':' + password);
xhr.setRequestHeader("Authorization", "Basic " + base64);
},
dataType: 'jsonp',
success: function(data) {
console.log(data);
},
error: function(a,b,c) {
//console.log(a,b,c);
}
});
});
Q1
You don't specify how you visit the protected URL (dev.driz.co.uk/basic/locked). Are you sure that the way you are doing it you are setting up the request headers properly? You need to Base64 encode the username/password.
When your first request fails the browser jumps in with the prompt and to be succeeding means that the browser does it properly for you the second time.
Have a look at you request headers to see what you send the first time and what the browser sends the second.
Q2
When basic auth fails your server sends a 401 with a header WWW-Authenticate:Basic which is picked up from the browser and you are presented with the prompt. That is build in normal behavior for all browsers since ages, you can't change that.
About your issue with canceling and being redirected to login, Auth had some API changes after 2.4 that are highlighted in the book. Before version 2.4 you are always redirected to loginAction.
Finally, let Auth do the work for you by setting it up properly and don't attempt to hardwire the responses yourself like in the code you suggest. You also shouldn't ever be using php's header() in cakephp, use CakeRequest::header() instead.
Q3
Answered in Q2, you can't have Basic and 401 not trigger the prompt. Either change the required authentication header (by perhaps setting a name like Basic-x instead of Basic) or don't send the response code 401 on failure but send i.e. 200 or 400 and add an error message explaining the situation.

Resources