Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

phone login support #2

Merged
merged 3 commits into from
Oct 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
overrideCreateUser: (createUser, _, args, context) {
// Optionally override createUser if you need custom logic
Expand Down Expand Up @@ -202,6 +203,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.
Expand Down
1 change: 1 addition & 0 deletions package.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Package.onUse(function(api) {
'oauth',
'service-configuration',
'accounts-oauth',
'sha',
],
'server'
);
Expand Down
2 changes: 1 addition & 1 deletion src/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type LoginMethodResponse {
# Token of the connection
token: String!
# Expiration date for the token
tokenExpires: Float!
tokenExpires: String!
# The logged in user
user: User
}
Expand Down
15 changes: 15 additions & 0 deletions src/Mutation/createUserWithPhone.js
Original file line number Diff line number Diff line change
@@ -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})
}
29 changes: 19 additions & 10 deletions src/Mutation/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import loginWithPassword from './loginWithPassword';
import logout from './logout';
import changePassword from './changePassword';
import createUser from './createUser';
import verifyEmail from './verifyEmail';
import resendVerificationEmail from './resendVerificationEmail';
import forgotPassword from './forgotPassword';
import resetPassword from './resetPassword';
import oauth from './oauth';
import hasService from './oauth/hasService';
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'
import hasService from './oauth/hasService'

export default function(options) {
const resolvers = {
Expand Down Expand Up @@ -35,5 +38,11 @@ export default function(options) {
resolvers.resetPassword = resetPassword;
}

if (hasService(options, 'phone')) {
resolvers.loginWithPhone = loginWithPhone
resolvers.createUserWithPhone = createUserWithPhone
resolvers.resendPhoneVerification = resendPhoneVerification
}

return { Mutation: resolvers };
}
14 changes: 14 additions & 0 deletions src/Mutation/loginWithPhone.js
Original file line number Diff line number Diff line change
@@ -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)
}
4 changes: 4 additions & 0 deletions src/Mutation/oauth/hasService.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,9 @@ export default function (options, service) {
return options.loginWithLinkedIn
}

if (service === 'phone') {
return options.loginWithPhone
}

return false
}
15 changes: 15 additions & 0 deletions src/Mutation/resendPhoneVerification.js
Original file line number Diff line number Diff line change
@@ -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
}
}
14 changes: 14 additions & 0 deletions src/Mutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -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): AuthSuccessResponse
# Send verification code to phone.
resendPhoneVerification (phone: String): AuthSuccessResponse
}`)
}

mutations.push(`
type Mutation {
# Log the user out.
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const initAccounts = function(givenOptions) {
loginWithGoogle: false,
loginWithLinkedIn: false,
loginWithPassword: true,
loginWithPhone: false,
overrideCreateUser: null, // createUser, args, context
};
const options = {
Expand Down