Users

At the core of many apps, there is a notion of user accounts that lets users access their information in a secure manner. We provide a specialized user class called Moralis.User that automatically handles much of the functionality required for user account management.

With this class, you'll be able to add user account functionality in your app.

Moralis.User is a subclass of Moralis.Object, and has all the same features, such as flexible schema, automatic persistence, and a key value interface. All the methods that are on Moralis.Object also exist in Moralis.User. The difference is that Moralis.User has some special additions specific to user accounts.

Sign Up With Username

It's also possible to authenticate without a wallet via user name and password. This makes use of the built in Moralis.User class. This class extends Moralis.Object with some extra attributes:

  • username: the username for the user (required)

  • password: the password for the user (required on signup)

  • email: the email address for the user (optional)

Use Moralis.User.signUp(username, password) to create a new user:

const user = new Moralis.User();
user.set("username", "my name");
user.set("password", "my pass");
user.set("email", "[email protected]");
// other fields can be set just like with Moralis.Object
user.set("phone", "415-392-0202");
try {
await user.signUp();
// Hooray! Let them use the app now.
} catch (error) {
// Show the error message somewhere and let the user try again.
alert("Error: " + error.code + " " + error.message);
}

This call will asynchronously create a new user in your Moralis App. Before it does this, it also checks to make sure that both the username and email are unique. Also, it securely hashes the password in the cloud using bcrypt. We never store passwords in plaintext, nor will we ever transmit passwords back to the client in plaintext.

Note that we used the signUp method, not the save method. New Moralis.Users created with a username should always be created using the signUp method. Subsequent updates to a User can be done by calling save.

If a signup isn’t successful, you should read the error object that is returned. The most likely case is that the username or email has already been taken by another user. You should clearly communicate this to your users, and ask them try a different username.

You are free to use an email address as the username. Simply ask your users to enter their email, but fill it in the username property — Moralis.User will work as normal. We’ll go over how this is handled in the reset password section.

Log In With Username

Of course, after you allow users to sign up, you need to let them log in to their account in the future. To do this, you can use the class method logIn.

const user = await Moralis.User.logIn("myname", "mypass");
// Do stuff after successful login.

By default, the SDK uses the GET HTTP method. If you would like to override this and use a POST HTTP method instead, you may pass an optional Boolean property in the options argument with the key usePost.

const user = await Moralis.User.logIn("myname", "mypass", { usePost: true });
// Do stuff after successful login.

Verifying Emails

Enabling email verification in an application’s settings allows the application to reserve part of its experience for users with confirmed email addresses. Email verification adds the emailVerified key to the Moralis.User object. When a Moralis.User’s email is set or modified, emailVerified is set to false. Moralisthen emails the user a link which will set emailVerified to true.

There are three emailVerified states to consider:

  1. true - the user confirmed his or her email address by clicking on the link Moralisemailed them. Moralis.Users can never have a true value when the user account is first created.

  2. false - at the time the Moralis.User object was last refreshed, the user had not confirmed his or her email address. If emailVerified is false, consider calling fetch on the Moralis.User.

  3. missing - the Moralis.User was created when email verification was off or the Moralis.User does not have an email.

Reset Password

It’s a fact that as soon as you introduce passwords into a system, users will forget them. In such cases, our library provides a way to let them securely reset their password.

To kick off the password reset flow, ask the user for their email address, and call:

Moralis.User.requestPasswordReset("[email protected]")
.then(() => {
// Password reset request was sent successfully
}).catch((error) => {
// Show the error message somewhere
alert("Error: " + error.code + " " + error.message);
});

This will attempt to match the given email with the user’s email or username field, and will send them a password reset email. By doing this, you can opt to have users use their email as their username, or you can collect it separately and store it in the email field.

The flow for password reset is as follows:

  1. User requests that their password be reset by typing in their email.

  2. Moralis sends an email to their address, with a special password reset link.

  3. User clicks on the reset link, and is directed to a special Moralis page that will allow them type in a new password.

  4. User types in a new password. Their password has now been reset to a value they specify.

Note that the messaging in this flow will reference your app by the name that you specified when you created this app on Moralis.

Current User

It would be bothersome if the user had to log in every time they open your app. You can avoid this by using the cached current Moralis.User object.

Please note that this functionality is disabled by default on Node.js environments (such as React Native) to discourage stateful usages on server-side configurations. To bypass this behavior on this particular use case, call once Moralis.User.enableUnsafeCurrentUser() right before using any cached-user related functionalities.

Whenever you use any signup or login methods, the user is cached in localStorage, or in any storage you configured via the Moralis.setAsyncStorage method. You can treat this cache as a session, and automatically assume the user is logged in:

const currentUser = Moralis.User.current();
if (currentUser) {
// do stuff with the user
} else {
// show the signup or login page
}

When using a platform with an async storage system you should call currentAsync() instead.

Moralis.User.currentAsync().then(function(user) {
// do stuff with your user
});

You can clear the current user by logging them out:

Moralis.User.logOut().then(() => {
const currentUser = Moralis.User.current(); // this will now be null
});

Setting the Current User

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.

Moralis.User.become("session-token-here").then(function (user) {
// The current user is now set to user.
}, function (error) {
// The token could not be validated.
});

Security For User Objects

The Moralis.User class is secured by default. Data stored in a Moralis.User can only be read or modified by that user.

A Cloud Function can be used to bypass this restriction however, by using the useMasterKey option.

Specifically, you are not able to invoke any of the save or delete methods unless the Moralis.User was obtained using an authenticated method, like logIn or signUp. This ensures that only the user can alter their own data.

The following illustrates this security policy:

const user = await Moralis.User.logIn("my_username", "my_password");
user.set("username", "my_new_username");
await user.save();
// This succeeds, since the user was authenticated on the device
// Get the user from a non-authenticated method
const query = new Moralis.Query(Moralis.User);
const userAgain = await query.get(user.objectId);
userAgain.set("username", "another_username");
await userAgain.save().catch(error => {
// This will error, since the Moralis.User is not authenticated
});

The Moralis.User obtained from Moralis.User.current() will always be authenticated.

If you need to check if a Moralis.User is authenticated, you can invoke the authenticated method. You do not need to check authenticated with Moralis.User objects that are obtained via an authenticated method.

Encrypting Current User

Often you may want to be more careful with user information stored in the browser, if this is the case you can encrypt the current user object:

Moralis.enableEncryptedUser();
Moralis.secret = 'my Secrey Key';
  • It's important to remember that this function will not work if Moralis.secret is not set.

  • Also note that this only works in the browser.

Now the record in Local Storage looks like a random string and only can be read using Moralis.User.current() You can check if this feature is enabled with the function Moralis.isEncryptedUserEnabled().

Security For Other Objects

The same security model that applies to the Moralis.User can be applied to other objects. For any object, you can specify which users are allowed to read the object, and which users are allowed to modify an object. To support this type of security, each object has an access control list, implemented by the Moralis.ACL class.

The simplest way to use a Moralis.ACL is to specify that an object may only be read or written by a single user. This is done by initializing a Moralis.ACL with a Moralis.User: new Moralis.ACL(user) generates a Moralis.ACL that limits access to that user. An object's ACL is updated when the object is saved, like any other property. Thus, to create a private note that can only be accessed by the current user:

const Note = Moralis.Object.extend("Note");
const privateNote = new Note();
privateNote.set("content", "This note is private!");
privateNote.setACL(new Moralis.ACL(Moralis.User.current()));
privateNote.save();

This note will then only be accessible to the current user, although it will be accessible to any device where that user is signed in. This functionality is useful for applications where you want to enable access to user data across multiple devices, like a personal todo list.

Permissions can also be granted on a per-user basis. You can add permissions individually to a Moralis.ACL using setReadAccess and setWriteAccess. For example, let's say you have a message that will be sent to a group of several users, where each of them have the rights to read and delete that message:

const Message = Moralis.Object.extend("Message");
const groupMessage = new Message();
const groupACL = new Moralis.ACL();
// userList is an array with the users we are sending this message to.
for (let i = 0; i < userList.length; i++) {
groupACL.setReadAccess(userList[i], true);
groupACL.setWriteAccess(userList[i], true);
}
groupMessage.setACL(groupACL);
groupMessage.save();

You can also grant permissions to all users at once using setPublicReadAccess and setPublicWriteAccess. This allows patterns like posting comments on a message board. For example, to create a post that can only be edited by its author, but can be read by anyone:

const publicPost = new Post();
const postACL = new Moralis.ACL(Moralis.User.current());
postACL.setPublicReadAccess(true);
publicPost.setACL(postACL);
publicPost.save();

Operations that are forbidden, such as deleting an object that you do not have write access to, result in a Moralis.Error.OBJECT_NOT_FOUND error code. For security purposes, this prevents clients from distinguishing which object ids exist but are secured, versus which object ids do not exist at all.