settlin:accounts-phone

v1.1.1Published 8 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

I have removed libphonenumber-js from the dependencies so that the library is not added twice if you also use it in your app. If you don't then anyways it will be loaded once.

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.

The flow

Use a simple Meteor method,

1function sendOtpViaSms(otp) {.....} // the function through which you send sms
2
3Meteor.methods({
4	sendOtpForLogin: function(to) {
5		if (Meteor.isClient) return null;
6
7		// otp must be generated on the server and never revealed to the client
8		check(to, String);
9
10		let user = Meteor.users.findOne({'phones.number': to});
11
12		// if there is no user with the given phone number, we create a new one.
13		// Accounts.createUser is available only on the server and creates a new user with two fields: `phones` and `services`. It ensures that the phone numbers are always unique for users.
14		if (!user) user = {_id: Accounts.createUserWithPhone({phone: to})};
15
16		// send otp as sms
17		let otp = Math.round(Random.fraction() * 100000);
18
19		// Accounts.setPhoneOtp sets the otp in the `__otps` collection: {phone, otp, purpose: '__login__'}.
20		Accounts.setPhoneOtp(user._id, otp);
21	},
22});

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 Create a user directly on the server. Unlike the client version, this does not log you in as this user after creation.
38 * @locus Server
39 * @param {Object} options Object with arguments. Needs just {phone: String} for now.
40 * @returns {String} userId The newly created user's _id
41 */
42Accounts.createUserWithPhone = function(options) {...};
43
44/**
45 * @summary finds user by doing a phone number search. Throws error if multiple found.
46 * @param {String} phone phone number.
47 * @return {Object} user document
48 */
49Accounts.findUserByPhone = function(phone) {...};

Client

1/**
2 * @summary Log the user in with a password.
3 * @locus Client
4 * @param {Object} options phone and otp
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(options, callback) {...};

both

1/**
2 * @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
3 * @locus Both
4 * @param {String}  phone phone number
5 * @return {String} sanitized phone number. Tweaked for Indian numbers, but works for other countries as well.
6 */
7
8Accounts.sanitizePhone = function(phone) {...};

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