I'm trying to access the data stored in local storage using function testData(), but for some reason my console prints out {ob: Observer}. I set the data inside function login() and I can also see it in my browser.
I'm new to front-end development, so I would appreciate any help.
Vue
testData() {
console.log(this.$auth.$storage.getUniversal('user'))
},
login() {
this.$auth.loginWith('local', {
data: {
username: this.username,
password: this.password
}
}).then(response => {
const user = response.data
this.$auth.setUser(user)
this.$auth.$storage.setUniversal('user', user.username, true)
})
},
localStorage
You can access the nuxt/auth user with this.$auth.$storage.state.user properly (or even this.$auth.user).
When you see Observer, it just means that it's watching for your data but the object is currently empty, it's actually a getter.
I've tried to refresh and in that case, this is indeed empty.
But if you logout and log back in, or just log in as usually and check the value via a button or alike, you'll see it populated with email and password.
Meanwhile, I'm not sure that this.$auth.$storage.setUniversal('user', user.username, true) is needed because the module is doing that for you.
What are you actually want to do here?
Related
I'm using the PasswordCredential API in Google Chrome and Edge to store authentication credentials, however this data is not saved.
I'm using the code below, and I only fire it if my AJAX login is successful.
var cred = new PasswordCredential({
name: account,
id: email,
password: password,
iconURL: 'https://example.com/favicon.ico'
});
navigator.credentials.store(cred).then(() => {
if (redirect !== undefined) {
$window.location.href = 'dashboard.html';
}
});
If inside the then function of the .store I put it to pull the saved data, null data is displayed.
navigator.credentials.store(cred).then(() => {
navigator.credentials.get({ password: true }).then(function (auth) {
console.log(auth); //Return NULL
console.log(auth.password); //Returns that does not exist
console.log(auth.id); //Returns that does not exist
console.log(auth.name); //Returns that does not exist
});
});
What did I do wrong in my code?
Edit
I believe I found the problem, as the user chooses and not saving the credentials in the browser the promise is pending.
Is there any way to do this automatically without the user having to manually save?
And how do I handle the promise when it completes?
As per W3C it store api will return the promise to make sure it has raised proper request to browser or not, it will not tell if use save or not. If you want to achieve this, you may create setInterval where you can regularly check by calling get from store.
In Reference to save, promise already shows fulfilled as below:
I am attempting to add MFA for user authentication to an already existing solution (built in Angular) for device management within AWS Cognito.
I am having trouble figuring out how to handle this particular response well from a user-experience perspective. It actually feels broken, so would love if anyone else has experience pain points here.
See Use Case 23. for example implementation, mine is below:
authenticate(username: string, password: string): Observable<any> {
// init cognitoUser here
return new Observable((observer) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result: any) => {},
onFailure: (err: Error) => {},
mfaRequired: (codeDeliveryDetails: any) => {
// SMS has just been sent automatically
// and it needs to be confirmed within this scope
// The example linked requests the code via `confirm()`
// which is awful UX...and since this is a service
// probably non-compliant with best practice
// However, without this `confirm` at this point in
// time, we have no confirmationCode below
cognitoUser.sendMFACode(confirmationCode, {
onSuccess: (result) => {
observer.next(result);
observer.complete();
}, onFailure: (err: Error) => {
observer.error(err);
observer.complete();
}
});
}
});
});
}
Expected:
If the user authenticates successfully but has not added this device through MFA, we can manage the redirect to appropriate confirmation code form page and trigger the sendMFACode function manually (perhaps through some sort of limited session?)
Issue/s:
we don't have a session, so we have no way of asking the user the MFA code sent automatically outside of this login screen...catch 22?
adding another show/hide field in the login form doesn't work as it would hit the sendMfaCode function multiple times, resulting in multiple SMS codes sent.
Has anyone had any luck stepping out of this flow?
Whilst I’m sure very talented people worked on the amazon-cognito-identity-js API, it is just straight up badly designed. Thus why it’s been depricated. My personal advise would be to migrate to Amplify, which makes me much less angry.
With Amplify you can do these ones.
import Amplify from 'aws-amplify'
import Auth from '#aws-amplify/auth'
let mfaRequired = false
Amplify.configure({
Auth: {
userPoolWebClientId: '',
userPoolId: ''
}
})
const logUserIn = (user) => {
// Go forth and be happy
}
// Run me on your login form's submit event
const login = async (username, password) => {
const user = await Auth.signIn(username, password)
if (user.challengeName === 'SMS_MFA') {
// Change UI to show MFA Code input
mfaRequired = true
return
}
return logUserIn(user)
}
// Run me when the user submits theire MFA code
const senfMfaCode = async (mfaCode) => {
const user = await Auth.confirmSignIn(mfaCode)
return logUserIn(user)
}
BUT if for some sad reason you need to keep using amazon-cognito-identity-js don’t worry. I got you.
Just keep the cognitoUser object stored outside the callback. The documentation is a little misleading because it only show’s self contained examples but there’s no reason that you can’t notify your UI when MFA is required and then call cognitoUser.sendMFACode() later.
Just remember that the documentation show’s the passing of this to sendMFACode() for scoping (which is terrible) but you can just declare your callbacks as a variable and share it between your authenticateUser() and sendMFACode() functions (or as many functions as you like).
import { CognitoUserPool, AuthenticationDetails, CognitoUser } from 'amazon-cognito-identity-js'
export let mfaRequired = false
export let cognitoUser = null
export const cognitoCallbacks = {
mfaRequired () {
// Implement you functionality to show UI for MFA form
mfaRequired = true
},
onSuccess (response) {
// Dance for joy the code gods be glorious.
},
onFailure () {
// Cry.
}
}
export const logUserIn = payload => {
cognitoUser = new CognitoUser({
Username: 'Matt Damon',
Pool: new CognitoUserPool({
UserPoolId: '',
ClientId: ''
})
})
return cognitoUser.authenticateUser(new AuthenticationDetails(payload), cognitoCallbacks)
}
export const sendMfaCode = MFACode => {
cognitoUser.sendMFACode(MFACode, cognitoCallbacks)
}
That’s a super basic implementation and on top of that you could,
Just overwrite the mfaRequired function in an external module to do whatever you want.
Wrap the whole thing in a pub/sub plugin and subscribe to events.
Hope that helps!
I know this is an old question, but I thought this answer might be helpful for anyone who is still using the amazon-cognito-identity-js API instead of Amplify. #stwilz's answer works somewhat, but there are a few complications that come when you stray too far away from the documentation's use cases (and might come about when doing TOTP MFA instead of SMS MFA). I've created a workaround to address situations where you might get errors like Invalid Access Token, Missing parameter Session, or Invalid session for the user.
If you need to use something like sendMFACodeoutside of the callbacks, it's not enough to just keep cognitoUser stored outside the callback. You actually have to call the authenticateUser function again, then call the sendMFACode within the callback. It gets more complicated with verifySoftwareToken for TOTP, where you actually have to store the Cognito user object and then reassign it when calling authenticateUser again.
If none of this makes sense, I've created a simple Github Gist that uses React and amazon-cognito-identity-js to show how such a flow would work. It's here: https://gist.github.com/harve27/807597824720d0919476c0262e30f587
I have a project using Firebase for the authentication. When I log into my project, sometimes the firebase.auth().currentUser method returns info from some other user. Sometimes I get the info from the actual current user and sometimes the previously signed in user - when this happens, the only way to correct the problem and get data for the correct user is to logout and sign back in again.
My login method:
onLoginClick = () => {
firebase.auth().signInWithEmailAndPassword(this.state.email.trim(), this.state.password.trim())
.then((user) => {
//Some redirects depending on my users role
})
.catch((error) => {
console.log(error, error.message);
if (error.code == "auth/user-not-found" || error.code == "auth/wrong-password") {
//Handle error
}
});
}
And my Logout method:
onLogoutClick = () => {
firebase.auth().signOut().then(function () {
this.props.history.replace("/")
}).catch(function (error) {
console.log(error);
});
}
They're pretty standard but seems like I'm doing something wrong. I've tried clearing the sessionStorage and the localStorage on the logout method but that didn't help.
UPDATE:
I've tried with some suggestions like doing:
firebase.auth().signOut().then(() => {
firebase.auth().signInWithEmailAndPassword(email, password).then((user) => {
//My redirects and everything
})
})
But this doesn't work.
Also, I've noticed that when I log in and use wrong credentials, the sessionStorage gets an entry with the previously signed in user, even though I signed him out.
I'm pretty sure that during the initialization of a new login session, until it is complete, currentUser hasn't been updated yet; use the user parameter when one is passed in on those methods. Because the login is still in progress, there is not yet a currentUser, so it passes the user in progress via the user parameter. (I think this means it is likely that it will be null the first time someone logs in, and it will be the previous one thereafter, unless it's cleared on logout by some code.)
Use the user parameter when it is provided, such as in the onAuthStateChanged handler. See the first example here, and the starred note in the blue box farther down that same page.
I have a simple Backbone.js app with User model with different roles and I use json-server to emulate some backend basics. I need to make a basic authentication -- i.e. I need my User to be able to login and save his session somewhere (for that he wouldn't need to sign in each time he refreshes his browser). I've got a db.json file where I already have some users:
{
"users": [
{
"login": "admin",
"password": "password",
"role": "admin",
"id": 1
}
]
}
and here is my User model:
var User = Backbone.Model.extend({
defaults: {
login: "",
password: "",
role: ""
},
// Updated
url: function () {
return "http://localhost:3000/users?login=" +
this.attributes.login + "&password=" + this.attributes.password;
}
});
I don't get quite good how could I manage authentication (i.e. entering login and password in form and storing the user session without proper backend). I thought about making a token field in my User model and filling in in each time user signs in and saving it in cookies, but I don't get how could I do that either way. I would be very grateful if someone could help me with this task.
ADDDED This is my login function in my view:
signIn: function () {
var login = $('#js-login').val();
var password = $('#js-password').val();
if (login && password) {
var currentUser = new User({
login: login,
password: password
});
currentUser.fetch({
success: function () {
console.log(currentUser.toJSON());
},
error: function (err) {
console.log(err);
}
});
}
}
But instead of finding a user from my json-server it just creates a new user with all empty attributes except of values of #js-login and #js-password input fields
ADDED I guess I should find my users by the query in url above in my collection, but I don't actually get how I would manage that
Repo with my project
This is simplified flow for your app:
Each time user open your website, check his cookies.
If cookies contain user info (saved username, password), check match with the info in your DB. If matched, go to home page. Otherwise, clear cookies, go to login page
If cookies not contain user info, go to login page
In login page, after user success logged in, save user info to cookies for next time check.
You can use some mechanism to encode user info (tokens, encryption...) to secure info stored in cookies/sessions. But store authentication DB in client is really weak security point. Sample code below:
Model:
var User = Backbone.Model.extend({
url: function () {
return "users?login" + this.attributes.login + "&password=" + this.attributes.password;
},
isAdmin: function () {
return (this.get("role") == "admin");
}
});
In your view:
// Load username password from cookie (just simple example)
var username = $.cookie("username"),
password = $.cookie("password");
if (username && password) {
var userModel = new User({
login: username,
password: password
});
userModel.fetch({
success: function () {
if (userModel.isAdmin) {
// e.g. go to admin page
} else {
// e.g. go to normal user page
}
// Save to cookie/session here
},
error: function () {
// Go to login page
}
});
} else {
// Go to login page
}
About cookie, you can refer How do I set/unset cookie with jQuery?
About getting username/password input form, you can just use simple jquery selector (very easy to google for it, e.g. https://www.formget.com/jquery-login-form/)
Here you can refer to this plugin that uses mostly the jquery functions as mentioned in the documentation here
I would not be going into much detail as the documentaion is quite clear.
This refers to the authentication with the jquery
Now IF you want to authenticate the user using backbone.js
if the route came back with {loggedIn: false} the backbone router would send the user to the login/register pages only. But if it came back with a users profile information then it would obviously mean he had a session.
wire up $.ajax to respond to 401 (Unauthorized) status codes.
Also to mention as stated in this stackoverflow thread
Hope it may be able to help you a bit.
Here is the step by step guide to authenticate with backbone.js
I'm having trouble interacting with my Parse data in node.js. I'm able to login successfully, but Parse.User.current() returns null. After running the below code, I'd like to query data that has ACL read/write only for that user. Currently, that query returns empty, but if I change that data to public read/write, I can see the results of the query output in the terminal.
Here is my node.js code:
Prompt.get([{
name: 'username',
required: true}, {
name: 'password',
hidden: true}], function (err, result) {
if (err) {
console.log('Error: ' + err);
} else {
Parse.User.logIn(result.username, result.password, {
success: function(user) {
console.log('LOGGED IN');
console.log(user);
console.log(Parse.Session.current());
console.log(Parse.User.current());
... (query happens below this)
And my console output:
prompt: username: pablo
prompt: password:
LOGGED IN
ParseUser { _objCount: 0, className: '_User', id: 'EXyg99egkv' }
ParsePromise {
_resolved: false,
_rejected: true,
_resolvedCallbacks: [],
_rejectedCallbacks: [],
_error: 'There is no current user.' }
null
Thanks in advance.
Is this not a usecase for Parse.User.become()? From the parse docs:
If you’ve created your own authentication routines, or otherwise
logged in a user on the server side, you can now pass the session
token to the client and use the become method. This method will ensure
the session token is valid before setting the current user.
Parse.User.become("session-token-here").then(function (user) {
// The current user is now set to user.
}, function (error) {
// The token could not be validated.
});
I had similar problems and found this Parse blog that explains the issue:
Also in Cloud Code, the concept of a method that returns the current user makes sense, as it does in JavaScript on a web page, because there’s only one active request and only one user. However in a context like node.js, there can’t be a global current user, which requires explicit passing of the session token. Version 1.6 and higher of the Parse JavaScript SDK already requires this, so if you’re at that version, you’re safe in your library usage.
You can execute queries with user credentials in a node.js environment like this:
query.find({ sessionToken: request.user.getSessionToken() }).then(function(data) {
// do stuff with data
}, function(error) {
// do stuff with error
});
If you wish to validate that token before using it, here's an explanation of how you could go about doing that:
one way would be to query for an object known to be only readable by the user. You could have a class that stores such objects, and have each one of them use an ACL that restricts read permissions to the user itself. If running a find query over this class returns 0 objects with a given sessionToken, you know it's not valid. You can take it a step further and also compare the user object id to make sure it belongs to the right user.
Session tokens cannot be queried even with the master key.