Search code examples
node.jsvonage

How to resolve 'system:error:invalid-token' In Nexmo Vonage SDK changing to a new app in the same account


I am using "@vonage/server-sdk": "2.10.7-beta-2" package on server to create users in Vonage. To create the user, I used this API

const Vonage = require('@vonage/server-sdk');

const v = new Vonage({
 apiKey: config.voipConfig.key,
 apiSecret: config.voipConfig.secret,
 applicationId: config.voipConfig.appId,
 privateKey: config.voipConfig.privateKeyPath
};

v.users.create({
 "name": payload.username,
 "display_name": payload.displayName
}, (error: any, result: any) => {
});

Everything was working fine. But when I created a new application in vonage account and used new configs, it started to throw the following error

{
      description: 'You did not provide a valid token. Please provide a valid token.',
      code: 'system:error:invalid-token'
    }

I have checked the details multiple times and not sure what is wrong. The new credentials are from completely new account.

Any help would be much appreciated.


Solution

  • Looks like you are using the Vonage Conversations API to create a user. In good practice, we usually use dotenv to store our .env variables. If you are using a public github repo, remember to add *.env to your .gitignore.

    npm install dotenv

    // .env
    API_KEY=
    API_SECRET=
    APPLICATION_ID=
    APPLICATION_PRIVATE_KEY_PATH=
    TO_NUMBER=<YOUR CELL NUMBER>
    VIRTUAL_NUMBER=<VONAGE VIRTUAL NUMBER>
    NGROK_URL=https://<URL>.ngrok.io
    

    For testing purposes. Can you make an outbound call with the snippet below? That'll test your credentials.

    Make sure to store the private.key in same directory as .env and outbound-call.js

    // outbound-call.js 
    require("dotenv").config();
    const API_KEY = process.env.API_KEY;
    const API_SECRET = process.env.API_SECRET;
    const APPLICATION_ID = process.env.APPLICATION_ID;
    const APPLICATION_PRIVATE_KEY_PATH = process.env.APPLICATION_PRIVATE_KEY_PATH;
    const TO_NUMBER = process.env.TO_NUMBER;
    const VIRTUAL_NUMBER = process.env.VIRTUAL_NUMBER;
    if (!API_KEY || !API_SECRET) {
      console.log("🔥 API_KEY or API_SECRET missing");
      process.exit(1);
    }
    if (!APPLICATION_ID || !APPLICATION_PRIVATE_KEY_PATH) {
      console.log("🔥 APPLICATION_ID or APPLICATION_PRIVATE_KEY_PATH missing");
      process.exit(1);
    }
    if (!TO_NUMBER || !VIRTUAL_NUMBER) {
      console.log("🔥 TO_NUMBER or VIRTUAL_NUMBER missing");
      process.exit(1);
    }
    const Vonage = require("@vonage/server-sdk");
    const vonage = new Vonage({
      apiKey: API_KEY,
      apiSecret: API_SECRET,
      applicationId: APPLICATION_ID,
      privateKey: APPLICATION_PRIVATE_KEY_PATH,
    });
    
    vonage.calls.create({
      to: [
        {
          type: "phone",
          number: process.env.TO_NUMBER,
        },
      ],
      from: {
        type: "phone",
        number: process.env.VIRTUAL_NUMBER,
      },
      ncco: [
        {
          action: "talk",
          text: "This is a text to speech call from Vonage",
        },
      ],
    });
    

    To test the Conversations API, you will need to enable Voice for your Vonage Application and set the answer Webhook. I use NGROK as well, so it should look like this. https://<URL>.ngrok.io/webhooks/answer

    When working with Conversations API, I usually do:

    1. Create a Conversation
    2. Create a User
    3. Create a Member

    and put that into the /webhooks/answer

    //server.js
    require('dotenv').config();
    let express = require('express');
    let cookieParser = require('cookie-parser');
    let logger = require('morgan');
    let app = express();
    let port = 5001;
    app.use(logger('dev'));
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use(cookieParser());
    app.use(express.static('public'));
    
    const NGROK_URL = process.env.NGROK_URL;
    
    const Vonage = require('@vonage/server-sdk');
    const vonage = new Vonage({
      apiKey: process.env.API_KEY,
      apiSecret: process.env.API_SECRET,
      applicationId: process.env.APPLICATION_ID,
      privateKey: process.env.APPLICATION_PRIVATE_KEY_PATH
    });
    
    app.post('/webhooks/answer', async (req, res) => {
      console.log('🚚  answer', req.body);
      let result = req.body;
    
      const createCallConversationPromise = (ConvName, ConvDisplayName) => new Promise((resolve, reject) => {
        vonage.conversations.create({
            "name": ConvName,
            "display_name": ConvDisplayName,
        }, (error, result) => error ? reject(error) : resolve(result));
      });
    
      const createCallUserPromise = (Name, DisplayName) => new Promise((resolve, reject) => {
        vonage.users.create({
            name: Name,
            display_name: DisplayName,
        }, (error, result) => error ? reject(error) : resolve(result));
      });
    
      const createCallMemberPromise = (ConvId, UserId) => {
        vonage.conversations.members.create(ConvId, {
          "action": "join", 
          "user_id": UserId, 
          "channel": {
            "type": "app"
          } 
        }, (error, result) => {
          if(error) {
            console.log('\n🔥 Error Creating Member', error);
          }
          else {
            console.log('\n✅ Created Member with ConvId', ConvId, 'and UserId',UserId)
            console.log(result);
        }
        })
      };
    
      try {
        let ConvName = result.from + result.to + result.conversation_uuid;
        console.log('n✅ ConvName', ConvName);
        let ConvDisplayName = result.from + result.to + result.conversation_uuid;
        const conversation = await createCallConversationPromise(ConvName, ConvDisplayName);
        process.env.CONVERSATION_ID = conversation.id;
        console.log('\n✅ CONVERSATION_ID', process.env.CONVERSATION_ID);
    
        let Name = result.from + result.conversation_uuid;
        let DisplayName = result.from;
        const callUser = await createCallUserPromise(Name, DisplayName);
        console.log('\n✅ UserId', callUser.id)
    
        let ConvId = conversation.id;
        let UserId = callUser.id;
        const memberUser = await createCallMemberPromise(ConvId, UserId);
    
        let ncco = [
          {
              action: "talk",
              text: "<speak><lang xml:lang='en-GB'>Welcome to Vonage Development inbound call testing</lang></speak>",
              voiceName: "Emma"
          },
        ];
        res.json(ncco);
      
      } catch (error) {
        console.log("🔥 Error", error);
        let ncco = [
          {
              "action": "talk",
              "text": "<speak><lang xml:lang='en-GB'>Error on Process Answer</lang></speak>",
              "voiceName": "Emma"
          }
        ];
        res.json(ncco);
      }
    });