I am trying to use a Firebase callable function to create a Twilio token for a React project. The project should allow video calls using Twilio's webRTC service. The code is based on the example here https://www.twilio.com/blog/video-chat-react-hooks. I am attempting to move the server code to obtain the Twilio token for the video service into the Firebase callable function.
My console gives the following output and errors:
error check 1: handleSubmit called
error check 2: getToken function retrieved from functions ƒ (r){return n.call(e,r,t||{})}
error check 4: token set
POST https://us-central1-vid-chat-app.cloudfunctions.net/getToken 500
Uncaught (in promise) Error: INTERNAL
at new m (error.ts:66)
at b (error.ts:175)
at P.<anonymous> (service.ts:244)
at tslib.es6.js:100
at Object.next (tslib.es6.js:82)
at a (tslib.es6.js:71)
Here is the error from the Firebase console
Unhandled error Error: accountSid is required
at new AccessToken (/srv/node_modules/twilio/lib/jwt/AccessToken.js:213:28)
at generateToken (/srv/index.js:9:12)
at videoToken (/srv/index.js:23:19)
at exports.getToken.functions.https.onCall (/srv/index.js:42:19)
at func (/srv/node_modules/firebase-functions/lib/providers/https.js:273:32)
at corsHandler (/srv/node_modules/firebase-functions/lib/providers/https.js:293:44)
at cors (/srv/node_modules/cors/lib/index.js:188:7)
at /srv/node_modules/cors/lib/index.js:224:17
at originCallback (/srv/node_modules/cors/lib/index.js:214:15)
at /srv/node_modules/cors/lib/index.js:219:13
These are the two main files I believe are relevant
React file
import React, { useState, useCallback } from 'react';
import firebase from './firebase'
import Lobby from './Lobby';
import Room from './Room';
const VideoChat = () => {
const [username, setUsername] = useState('');
const [roomName, setRoomName] = useState('');
const [token, setToken] = useState(null);
const handleUsernameChange = useCallback(event => {
setUsername(event.target.value);
}, []);
const handleRoomNameChange = useCallback(event => {
setRoomName(event.target.value);
}, []);
const handleSubmit = useCallback(async event => {
console.log("error check 1: handleSubmit called")
event.preventDefault();
const getToken = firebase.functions().httpsCallable('getToken')
console.log("error check 2: getToken function retrieved from functions", getToken)
getToken({ identity: username, room: roomName })
.then(result => {
console.log("error check 3: calling .then")
setToken(result.data)
})
console.log("error check 4: token set")
}, [username, roomName]);
const handleLogout = useCallback(event => {
setToken(null);
}, []);
let render;
if (token) {
render = (
<Room roomName={roomName} token={token} handleLogout={handleLogout} />
);
} else {
render = (
<Lobby
username={username}
roomName={roomName}
handleUsernameChange={handleUsernameChange}
handleRoomNameChange={handleRoomNameChange}
handleSubmit={handleSubmit}
/>
);
}
return render;
};
export default VideoChat;
Firebase function
const twilio = require("twilio");
const functions = require('firebase-functions');
const config = require('./config');
const AccessToken = twilio.jwt.AccessToken;
const { VideoGrant } = AccessToken;
const generateToken = config => {
return new AccessToken(
config.twilio.accountSid,
config.twilio.apiKey,
config.twilio.apiSecret
);
};
const videoToken = (identity, room, config) => {
let videoGrant;
if (typeof room !== "undefined") {
videoGrant = new VideoGrant({ room });
} else {
videoGrant = new VideoGrant();
}
const token = generateToken(config);
token.addGrant(videoGrant);
token.identity = identity;
return token;
};
const sendTokenResponse = (token, res) => {
res.set('Content-Type', 'application/json');
res.send(
JSON.stringify({
token: token.toJwt()
})
);
};
exports.getToken = functions.https.onCall((data, context)=>{
console.log('Peter error check getToken function called')
const identity = data.identity;
const room = data.room;
const token = videoToken(identity, room, config);
sendTokenResponse(token, res);
console.log('here is the token', token)
return token
});
Config file also contained in Firebase cloud function folder
module.exports = {
twilio: {
accountSid: process.env.TWILIO_ACCOUNT_SID,
apiKey: process.env.TWILIO_API_KEY,
apiSecret: process.env.TWILIO_API_SECRET,
chatService: process.env.TWILIO_CHAT_SERVICE_SID,
outgoingApplicationSid: process.env.TWILIO_TWIML_APP_SID,
incomingAllow: process.env.TWILIO_ALLOW_INCOMING_CALLS === "true"
}
};
tokenvariable is what you expect. You can view the logs for the cloud functions following the instructions in this linkaccountSidnot having a proper value per the error hat is being showned in the firebase functions logs, you could try logging the environment variables to confirm that. Let me know if placing the env file the same folder solves the issue.