0
votes

I am attempting to send a text (a one-time pass code) using Twilio, firebase and Google Functions, and using Postman.

I have run $ npm install --save [email protected] -rc.13 in the functions directory.

When I run $ firebase deploy, it completes. But on Postman, when I do POST, Body and feed a JSON { "phone": "555-5555" }, I get an "Error: could not handle the request."

I am able to send a text in Twilio Programmable SMS from my Twilio number to an actual outside number direct to the mobile phone. I'm using live credentials for Sid and AuthToken.

Is this an issue with Twilio, Google Functions and some configurations?

Here are the logs on Functions:

// White flag sign// Function execution took 1452 ms, finished with status: 'crash'

//Red Warning sign// TypeError: handler is not a function at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:26:41) at /var/tmp/worker/worker.js:676:7 at /var/tmp/worker/worker.js:660:9 at _combinedTickCallback (internal/process/next_tick.js:73:7) at process._tickDomainCallback (internal/process/next_tick.js:128:9)

Also, the google eslint forces consistent-return, which is why I put "return;" in the request-one-time-password.js. I cannot seem to turn it off by adding "consistent-return": 0 in eslintrc.

My code(with secret keys and phone numbers redacted):

//one-time-password/functions/service_account.js
has my keys copied and pasted.

//one-time-password/functions/twilio.js


const twilio = require('twilio');

const accountSid = 'redacted';
const authToken = 'redacted';

module.exports = new twilio.Twilio(accountSid, authToken);

//one-time-password/functions/request-one-time-password.js

const admin = require('firebase-admin');
const twilio = require('./twilio');

module.export = function(req, res) {
  if(!req.body.phone) {
    return res.status(422).send({ error: 'You must provide a phone number!'});
  }
  const phone = String(req.body.phone).replace(/[^\d]/g, '');

  admin.auth().getUser(phone).then(userRecord => {
      const code = Math.floor((Math.random() * 8999 + 1000));
    // generate number between 1000 and 9999; drop off decimals
    twilio.messages.create({
      body: 'Your code is ' + code,
      to: phone,
      from: '+redacted'
    }, (err) => {
      if (err) { return res.status(422).send(err); }

      admin.database().ref('users/' + phone).update({ code: code, codeValid: true }, () => {
        res.send({ success: true });
      })
  });
return;
  }).catch((err) => {
    res.status(422).send({ error: err })
  });
}

/////////////////////////////////
//one-time-password/functions/index.js

const admin = require('firebase-admin');
const functions = require('firebase-functions');
const createUser = require('./create_user');
const serviceAccount = require('./service_account.json')
const requestOneTimePassword = require('./request_one_time_password');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://one-time-password-650d2.firebaseio.com"
});

exports.createUser = functions.https.onRequest(createUser);

exports.requestOneTimePassword = 
functions.https.onRequest(requestOneTimePassword);
2
Is your Firebase project on Spark (free-tier) plan? If so, that might explain why you are seeing the error, because on the free tier, outbound networking requests are limited to Google services only. Check firebase.google.com/pricing and hover over the question mark next to Cloud FunctionsPat Needham
I'm on the blaze tier.bigmugcup
Can you show what the logs say within your Firebase console for when you attempt to access that http function?Pat Needham
Sure, I just updated the above after the fifth paragraph with the Firebase logs. Thanks.bigmugcup
It finally worked. The issue was that I had to get a new service account secret key, probably after upgrading to the Blaze tier. I wish Google had said that the key changes after upgrading, it would have save me hours. Thanks, Mr. Needham for your attention.bigmugcup

2 Answers

0
votes

You have

module.exports = new twilio.Twilio(accountSid, authToken);

on one line, and further down

module.export = function(req, res) { ... }.

Try changing export to exports.

0
votes

One thing that tripped me up for a long time was how twilio sent the request body to the cloud function. It sends it in a body object so to access your request body it will look something like this

req.body.body

On top of that it passed it as a JSON string so I had to JSON.parse()

Example I got working:

export const functionName= functions.https.onRequest((req, res) => {
    cors(req, res, () => {   
            let body = JSON.parse(req.body.body);
            console.log(body);
            console.log(body.service_id);
            res.send();
    });
});

This also may depend on the Twilio service you are using. I was using their Studio HTTP Request Module.

Hope this helps a little, not sure if it was your exact problem though :(