From 752e3d7f1bf8a411b4a6d852a05b366b225fc092 Mon Sep 17 00:00:00 2001 From: Ujwal Setlur Date: Thu, 31 May 2018 14:37:02 -0700 Subject: [PATCH 1/2] phone login support. Requires ujwal:acounts-phone meteor package. --- package.js | 3 ++- src/Mutation/createUserWithPhone.js | 15 +++++++++++++++ src/Mutation/index.js | 9 +++++++++ src/Mutation/loginWithPhone.js | 14 ++++++++++++++ src/Mutation/oauth/hasService.js | 4 ++++ src/Mutation/resendPhoneVerification.js | 15 +++++++++++++++ src/Mutations.js | 14 ++++++++++++++ src/index.js | 1 + 8 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/Mutation/createUserWithPhone.js create mode 100644 src/Mutation/loginWithPhone.js create mode 100644 src/Mutation/resendPhoneVerification.js diff --git a/package.js b/package.js index 55a4296..8b1d9a1 100644 --- a/package.js +++ b/package.js @@ -2,7 +2,7 @@ Package.describe({ name: 'cultofcoders:apollo-accounts', - version: '3.2.3', + version: '3.2.4', // Brief, one-line summary of the package. summary: 'Meteor accounts in GraphQL', // URL to the Git repository containing the source code for this package. @@ -29,6 +29,7 @@ Package.onUse(function(api) { 'oauth', 'service-configuration', 'accounts-oauth', + 'sha', ], 'server' ); diff --git a/src/Mutation/createUserWithPhone.js b/src/Mutation/createUserWithPhone.js new file mode 100644 index 0000000..fd4684e --- /dev/null +++ b/src/Mutation/createUserWithPhone.js @@ -0,0 +1,15 @@ +import {Meteor} from 'meteor/meteor' +import {Accounts} from 'meteor/accounts-base' + +export default async function (root, options, context) { + Meteor._nodeCodeMustBeInFiber() + if (!options.phone) { + throw new Error('Phone number is required') + } + + let userId = Accounts.createUserWithPhone(options) + if(userId) { + Accounts.sendPhoneVerificationCode(userId, options.phone); + } + return ({success: !!userId}) +} diff --git a/src/Mutation/index.js b/src/Mutation/index.js index a3a3c72..3612f6d 100644 --- a/src/Mutation/index.js +++ b/src/Mutation/index.js @@ -1,9 +1,12 @@ import loginWithPassword from './loginWithPassword' +import loginWithPhone from './loginWithPhone' import logout from './logout' import changePassword from './changePassword' import createUser from './createUser' +import createUserWithPhone from './createUserWithPhone' import verifyEmail from './verifyEmail' import resendVerificationEmail from './resendVerificationEmail' +import resendPhoneVerification from './resendPhoneVerification' import forgotPassword from './forgotPassword' import resetPassword from './resetPassword' import oauth from './oauth' @@ -25,5 +28,11 @@ export default function (options) { resolvers.resetPassword = resetPassword } + if (hasService(options, 'phone')) { + resolvers.loginWithPhone = loginWithPhone + resolvers.createUserWithPhone = createUserWithPhone + resolvers.resendPhoneVerification = resendPhoneVerification + } + return {Mutation: resolvers} } diff --git a/src/Mutation/loginWithPhone.js b/src/Mutation/loginWithPhone.js new file mode 100644 index 0000000..adcd59c --- /dev/null +++ b/src/Mutation/loginWithPhone.js @@ -0,0 +1,14 @@ +import callMethod from '../callMethod' +import {Meteor} from 'meteor/meteor' + + +export default async function (root, options, context) { + if (!options.phone) { + throw new Error('Phone number is required') + } + if (!options.verificationCode) { + throw new Error('Verification code is required') + } + + return callMethod(context, 'verifyPhone', options.phone, options.verificationCode) +} diff --git a/src/Mutation/oauth/hasService.js b/src/Mutation/oauth/hasService.js index b92b7ba..bfc7840 100644 --- a/src/Mutation/oauth/hasService.js +++ b/src/Mutation/oauth/hasService.js @@ -15,5 +15,9 @@ export default function (options, service) { return options.loginWithLinkedIn } + if (service === 'phone') { + return options.loginWithPhone + } + return false } diff --git a/src/Mutation/resendPhoneVerification.js b/src/Mutation/resendPhoneVerification.js new file mode 100644 index 0000000..d8dcfe8 --- /dev/null +++ b/src/Mutation/resendPhoneVerification.js @@ -0,0 +1,15 @@ +import callMethod from '../callMethod' +import {Meteor} from 'meteor/meteor' + + +export default async function (root, options, context) { + if (!options.phone) { + throw new Error('Phone number is required') + } + + callMethod(context, 'requestPhoneVerification', options.phone) + + return { + success: true + } +} diff --git a/src/Mutations.js b/src/Mutations.js index e757fea..261885c 100644 --- a/src/Mutations.js +++ b/src/Mutations.js @@ -23,6 +23,20 @@ export default function (options) { }`) } + if (hasService(options, 'phone')) { + mutations.push(` + type Mutation { + # Log the user in with a phone. + loginWithPhone (phone: String, verificationCode: String): LoginMethodResponse + + # Create a new user with a phone. + createUserWithPhone (phone: String, password: String, profile: CreateUserProfileInput): SuccessResponse + + # Send verification code to phone. + resendPhoneVerification (phone: String): SuccessResponse + }`) + } + mutations.push(` type Mutation { # Log the user out. diff --git a/src/index.js b/src/index.js index 9bb1eaf..12d309f 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ const initAccounts = function(givenOptions) { loginWithGoogle: false, loginWithLinkedIn: false, loginWithPassword: true, + loginWithPhone: false, }; const options = { ...defaultOptions, From 4c62ab05662d24a5298a52b92c8ab12fb59d6c5b Mon Sep 17 00:00:00 2001 From: Ujwal Setlur Date: Thu, 31 May 2018 15:33:38 -0700 Subject: [PATCH 2/2] Updated README.md for phone support. --- README.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d392e7a..6a21d50 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,14 @@ Initialize the package. ```js import { makeExecutableSchema } from 'graphql-tools'; -import { initAccounts } from 'meteor/nicolaslopezj:apollo-accounts'; +import { initAccounts } from 'meteor/cultofcoders:apollo-accounts'; import { load, getSchema } from 'graphql-load'; const { typeDefs, resolvers } = initAccounts({ loginWithFacebook: false, loginWithGoogle: false, loginWithLinkedIn: false, + loginWithPhone: false, loginWithPassword: true, }); @@ -198,6 +199,92 @@ loginWithGoogle({ accessToken }, apollo); * `apollo`: Apollo client instance. +#### Phone support + +Login support using phone number and verification code. Requires ujwal:accounts-phone package. + +``` +meteor add ujwal:accounts-phone +``` + +From your client, execute the following mutation: + +```graphql +mutation createUserWithPhone { + createUserWithPhone (phone: "+11234567890", profile: {name: "A Phone User"}) { + success + } + } +``` + +Server response: +```js +{ + "data": { + "createUserWithPhone": { + "success": true + } + } +} +``` + +If Twilio has been set up on the server, a verification code will be sent to the phone via SMS. + +To login with the verification code, use the following mutation: + +```graphql +mutation loginWithPhone { + loginWithPhone (phone: "+11234567890", verificationCode: "6593") { + id + token + tokenExpires + } + } +``` + +Server response: +```js +{ + "data": { + "loginWithPhone": { + "id": "eHMzRW9B685curZ63", + "token": "Kg9mESwmEAs6xraKZ_hPv0tzOvQpTgMPhWTNXDFCet0", + "tokenExpires": 1535581386595 + } + } +} +``` + +You can use the response to store the login token: + +```js +await setTokenStore.set(id, token, new Date(tokenExpires)); +``` + +To request a new verification code, use the following mutation: + +```graphql +mutation resendPhoneVerification { + resendPhoneVerification (phone: "+11234567890") { + success + } + } +``` + +Server response: + +```js +{ + "data": { + "resendPhoneVerification": { + "success": true + } + } +} +``` + +If Twilio has been set up, then the verification code will sent via SMS. + #### onTokenChange Register a function to be called when a user is logged in or out.