How to check user password in angular's strongloop SDK? - angularjs

I want to check the current user's password in order to allow him to change his/her password.
According to the user model docs, the way to do this is using the user.hasPassword method, by I get a "is not a function" error.
https://docs.strongloop.com/display/LB/User#user-prototype-haspassword
There is no reference to this in the angular SDK docs, so I'm guessing this method is not avalable from angular. https://docs.strongloop.com/display/public/LB/AngularJS+JavaScript+SDK#AngularJSJavaScriptSDK-Authentication
Any clues on how to accomplish this?

Sorry if this is just semantics, but if you are using the built in User model, you don't ever "check a user's password," you check if they are authenticated with a valid authToken that is set in a header.
But if you are trying to change a user's password and requiring them to log in before changing it, you can also just call User.login() and verify that you get a success response from the API. Then use the new password and persist it by updating the User instance with an update or updateAttributes.
See https://apidocs.strongloop.com/loopback-sdk-angular/#user
Will look something like this (warning: quick writeup, not tested!):
User.login({email: $scope.email, password: $scope.oldPassword}, function(response){
// user login was valid, now update user with new password by user id
//
User.prototype$updateAttributes({id: response.user.id}, {password: $scope.newPassword},
function(response) {
// success
}, function(response) {
// fail
});
}, function(response) {
// login failed, send to login screen
});

Related

NextAuth.js - Credentials authentication, adding reset password button

I am developing login system with next/auth and have credentials logging system implemented with invitation only system. Is there a way to add Reset password link to the generated /api/auth/signin page?
Your best bet would be to create your own custom signIn page (https://next-auth.js.org/configuration/pages) where you then can add the "reset password" functionality that you desire
I saw and used the one similar with this. Perhaps this can help you.
Send a post from my backend to create a new auth0 user. At this point the auth0 user.email_verified = false.
Send a post to trigger a password reset email for the new user.
{% if user.email_verified == false %}
<h1>Invitation to our awesome app</h1>
<p>Please verify your email address and set your initial password by clicking the following link:</p>
<p>Confirm my account</p>
{% else %}
<h1>Password Change Request</h1>
<p>You have submitted a password change request. </p>
<p>If it wasn't you please disregard this email and make sure you can still login to your account. If it was you, then to <strong>confirm the password change click here</strong>.</p>
{% endif %}
<p>If you have any issues with your account, please don’t hesitate to contact us at 1-888-AWESOMECO.</p>
<br>
Thanks!
<br>
Configure a redirect on the Password Reset email template so that when the user clicks the invitation link, they will be prompted to reset their password and then they will be redirected to our app, which will then ask them to login
I added an auth0 Rule to set email_verified = true on first login/password reset ( it was one of the canned options)
}
if (user.email_verified || !user.last_password_reset) {
return callback(null, user, context);
}
// Set email verified if a user has already updated his/her password
request.patch({
url: userApiUrl + user.user_id,
headers: {
Authorization: 'Bearer ' + auth0.accessToken
},
json: { email_verified: true },
timeout: 5000
},
function(err, response, body) {
// Setting email verified isn't propagated to id_token in this
// authentication cycle so explicitly set it to true given no errors.
context.idToken.email_verified = (!err && response.statusCode === 200);
// Return with success at this point.
return callback(null, user, context);
});
}
Next time we need to send them a password reset email it will use the “existing user” flavor of the template
The invitation email pw reset link has a configurable TTL – it defaults to 5 days. So if they don’t accept the invite it will eventually timeout (and we could send them another one if needed)

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!

Showing error message on MEAN website

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.

How to set the Access-Token for the password reset in LoopBack with the AngularJs SDK

My Project is based on the
Loopback Getting Started Tutorial 2
I use the AngularJs SDK on the Client-Side and I want to implement the "Password-Reset"-Function.
First there is the /reset-password view, where you can enter your email address and ask for another password.
Then you get a link send per email that directs you to /set-new-password/{{accessToken}}/{{userId}}
On this view, the user enters the password and submit it. Afterwards it should find the User by Id and update its password.
But for User.findById and User.updateById I need the access-token in the Request-Header.
"Normally" the Request-Header always contains the access-token after the login. But since it's a password-reset, I'm not logged in.
I can access the access-token via $stateparams, but how can I set it in the Request-Header,so I can still use the AngularJs-SDK?
(I hope everything is clear. English is not my native language)
Edit: I have found someone with nearly the same question here. The not accepted answer works for me now.
EditEdit: Doesn't work always.. Sometimes it doesn't change the "authorization"-parameter in the Header. Can't figure out why
The solution with the LoopBack AngularJs SDK
In your angularJs controller
.controller(function (UserAccount, $location, LoopBackAuth, $scope) {
var params = $location.search();
var access_token = params.access_token;
$scope.reset = function(inputs) {
LoopBackAuth.setUser(access_token);
UserAccount.setPassword({ newPassword: inputs.newPassword });
}
})
You need to implement error control and ideally check the password twice before sending.

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