settlin:accounts-phone

v1.3.4Published 3 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Accounts-Phone

Phone and OTP based login for Meteor.

Installation

In a Meteor app directory, enter:

meteor npm install --save libphonenumber-js
meteor add settlin:accounts-phone

libphonenumber-js is used by Accounts.sanitizePhone(). I do not include it as a dependency so that if one overwrites the sanitizePhone function, the library is not added in vain.

The database

In accordance with the current emails field used by accounts-password, we use phones field in the user document: {phones: [{number, verified: false}]}. The otp is stored in services.phone.otp.

You will need to create an index on the collection, to ensure performance

Meteor.otps.rawCollection().createIndex({phone: 1, purpose: 1}, {unique: true, name: 'phoneAndPurpose'});

The flow

Use a simple Meteor method,

1function sendOtpViaSms(otp) {.....} // the function through which you send sms
2
3Meteor.methods({
4 // to 
5 sendOtpForLogin: function(toPhone) {
6  if (Meteor.isClient) return null;
7
8  // otp must be generated on the server and never revealed to the client
9  check(toPhone, String);
10
11  // send otp as sms
12  let otp = Math.round(Random.fraction() * 100000);
13
14  // Accounts.setPhoneOtp sets the otp in the `__otps` collection: {phone, otp, purpose: '__login__'}.
15  Accounts.setPhoneOtp(toPhone, otp);
16 },
17});

Use this method to send otp whenever needed. Next, take the otp from the user and call,

Meteor.loginWithPhone({phone, otp}, callback);

This method works as any other Meteor.loginWith<Service> method.

Simple API

Server

1Meteor.otps; // the collection that contains otps in the form {phone, otp, purpose, createdAt} with an index created by: Meteor.otps._ensureIndex({phone: 1, purpose: 1}, {unique: true, name: 'phoneAndPurpose'});
2// not available on client
3
4/**
5 * @summary Set the otp for a user.
6 * @locus Server
7 * @param {String} userId The id of the user to update.
8 * @param {String} otp OTP
9 * @returns {Void} null
10 */
11Accounts.setPhoneOtp = function(userId, otp) {...};
12
13/**
14 * @summary Add a phone number for a user. Use this instead of directly
15 * updating the database. The operation will fail if there is a different user
16 * with same phone.
17 * @locus Server
18 * @param {String} userId The ID of the user to update.
19 * @param {String} newPhone A new phone number for the user.
20 * @param {Boolean} [verified] Optional - whether the new phone number should
21 * be marked as verified. Defaults to false.
22 * @returns {Void} null
23 */
24Accounts.addPhone = function(userId, newPhone, verified) {...};
25
26/**
27 * @summary Remove an phone number for a user. Use this instead of updating
28 * the database directly.
29 * @locus Server
30 * @param {String} userId The ID of the user to update.
31 * @param {String} phone The phone number to remove.
32 * @returns {Void} null
33 */
34Accounts.removePhone = function(userId, phone) {...};
35
36/**
37 * @summary finds user by doing a phone number search. Throws error if multiple found.
38 * @param {String} phone phone number.
39 * @return {Object} user document
40 */
41Accounts.findUserByPhone = function(phone) {...};
42
43/**
44 * @summary Log the user in with a password. Indian phone numbers are accepted without 91. For others, the country code is required. Uses https://github.com/halt-hammerzeit/libphonenumber-js
45 * @locus Server
46 * @param {String}  phone phone number
47 * @return {String} sanitized phone number. Tweaked for Indian numbers, but works for other countries as well.
48 */
49Accounts.sanitizePhone = function(phone) {...};

Client

1/**
2 * @summary Log the user in with a password.
3 * @locus Client
4 * @param {Object} options phone, otp and optional expectedUserId
5 * @param {Function} [callback] Optional callback. Called with no arguments on success,
6 *      or with a single `Error` argument on failure.
7 * @return {Void} null
8 */
9Meteor.loginWithPhone = function({
10 phone,
11 otp,
12 expectedUserId // optional. the user id which is expected for this phone. It is needed because phone numbers may not be unique, and at times we may need to check if the login is for an expected old user or a new user.
13}, callback) {...};
14
15/**
16 * @summary Log the user in with a password. Indian phone numbers are accepted without 91. For others, the country code is required. Uses https://github.com/halt-hammerzeit/libphonenumber-js, as dynamic import
17 * @locus Server
18 * @param {String}  phone phone number
19 * @return {String} sanitized phone number. Tweaked for Indian numbers, but works for other countries as well.
20 */
21Accounts.sanitizePhone = async function(phone) {...};

If you need a phone + password login, use https://github.com/okland/accounts-phone.