Node.js

Vonage Verify APIをバックエンドに追加する。

Vonage Server SDKの使用

Vonageは標準的なHTTP APIを公開している。つまり、理論的には、Verifyを統合するには、次のように送信すればよい。 生のHTTPリクエスト 例えば fetch, axiosなど)。

なぜVonage Node SDKを使用するのですか?

SDKの使用は、次のような点で役立つ:

  • 認証はより簡単で安全です:Verifyは秘密鍵によるJWTベースの認証を使用します。SDKは署名フローを正しく処理するため、ミスを犯す可能性が低くなります。

  • よりクリーンなコード:URL、ヘッダー、レスポンスフォーマットの解析を手作業で行う代わりに、以下のようなメソッドを呼び出します。 newRequest() そして checkCode().

  • より良いメンテナンス:VonageがAPIをアップデートしたり、機能を追加したりすると、SDKもそれに合わせてアップデートされます。

  • gotchas "の減少:リクエストフォーマットや期待されるフィールドのようなものは一貫して処理されます。

SDKを app.js ファイル:

require("dotenv").config();

const fs = require("fs");
const express = require("express");
const cors = require("cors");

const { Auth } = require("@vonage/auth");
const { Verify2 } = require("@vonage/verify2");

const app = express();
const port = process.env.PORT || 3000;

app.use(cors());
app.use(express.json());

// Create Vonage credentials (JWT auth)
const credentials = new Auth({
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: process.env.VONAGE_PRIVATE_KEY_PATH,
});

// Verify client (Verify API v2)
const verifyClient = new Verify2(credentials);

// Health check endpoint
app.get('/health', (req, res) => {
  res.json({ status: 'ok' });
});

// Run the server
app.listen(port, () => {
  console.log(`Backend listening on port ${port}`);
});

何が起きているんだ?

  • バックエンドはVonageに証明する必要がある: "このAPIを呼ぶことが許されている"
  • Vonageはその証明のために、あなたの秘密鍵で署名されたJWT(JSON Web Tokens)を使用します。
  • SDKはVonageを呼び出すたびに自動的にJWTを生成し、添付する。

検証を開始する: POST /verification

このエンドポイントは検証プロセスを開始する。モバイル・アプリは電話番号でバックエンドを呼び出します。その後、バックエンドはVonageに検証リクエストを開始するよう依頼します。

このエンドポイントでは何が起こるのか?

  1. ユーザーは携帯アプリに電話番号を入力する。
  2. モバイルアプリは電話番号をバックエンドに送信する。
  3. バックエンドがVerifyリクエストを開始する:
    • 初挑戦 サイレント認証
    • それが完了できない場合は、次のようになる。 ショートメール
app.post("/verification", async (req, res) => {
  const { phone } = req.body || {};

  if (!phone) {
    return res.status(400).json({ error: "Phone number is required." });
  }

  try {
    const result = await verifyClient.newRequest({
      brand: "DemoApp",
      workflow: [
        { channel: "silent_auth", to: phone },
        { channel: "sms", to: phone },
      ],
    });

    return res.json({
      request_id: result.requestId,
      check_url: result.checkUrl,
    });
  } catch (error) {
    const status = error?.response?.status || 500;
    const details = error?.response?.data || error?.message;

    console.error("Vonage Verify newRequest failed:", details);

    return res.status(status).json({
      error: "Failed to start verification",
      details: typeof details === "string" ? details : undefined,
    });
  }
});

理解する request_id そして check_url:

  • request_idこの検証のための一意の識別子。検証の「受付番号」のようなものと考えてください。

  • check_urlサイレント認証に使用されます。バックエンドはこのURLをモバイルアプリに返します。モバイルアプリは「このリクエストは電話番号のモバイルネットワークから来ている」ことを証明するためにこのURLを呼び出します。

検証コードをチェックする: POST /check-code

サイレント認証に失敗したり、利用できない場合、VonageはSMSにフォールバックし、ユーザーはコードを受け取ります。モバイルアプリはそのコードをバックエンドに送信します。 request_id.

app.post("/check-code", async (req, res) => {
  const { request_id, code } = req.body || {};

  if (!request_id || !code) {
    return res.status(400).json({ error: "request_id and code are required." });
  }

  try {
    const status = await verifyClient.checkCode(request_id, code);

    return res.json({
      verified: status === "completed",
      status,
    });
  } catch (error) {
    const status = error?.response?.status || 400;
    const details = error?.response?.data || error?.message;

    return res.status(status).json({
      error: "Failed to check code",
      details: typeof details === "string" ? details : undefined,
    });
  }
});

コールバック

コールバック ウェブフック)は、外部サービス(Vonage)がイベントを通知するために呼び出すことができるバックエンドのURLです。

バックエンドが常にVonageに問い合わせる代わりに: "サイレント・オース "はもう終わったのか?今は?今は?"

Vonageは結果をあなたにプッシュすることができる: "サイレント認証終了。これが最終ステータスです。"

そのプッシュ通知がコールバックだ。

なぜコールバックが役に立つのか?サイレント認証には時間がかかり、非同期で完了することがあります。コールバックを使うということは

  • バックエンドがVonageを何度もポーリングする必要はありません。
  • 検証の状態が変わると、決定的なイベントが発生します。
  • 実際のシステムでより良くスケールする

DashboardでコールバックURLを設定するには、Vonage Dashboardを開きます:

  1. アプリケーションへ
  2. アプリケーションを選択 → 編集
  3. ネットワーク・レジストリの検索
  4. ベリファイを有効にする(SA)
  5. コールバックURL(サーバーがリッスンする場所)を設定します:

https://your-domain.com/callback

:ローカルで稼動している場合、Vonageは次のような通信ができません。 http://localhost:3000.公開URL(一般的には次のようなトンネル)が必要です。 ングロク).

コールバックを実装するには、Expressアプリケーションに次のように新しいメソッドを追加する:

app.post("/callback", (req, res) => {
  console.log("Callback received:", req.body);
  return res.status(200).json({ ok: true });
});

今のところ、Vonageが何を送信したかを確認できるように、イベントをログに記録します。次のセクションでは、このイベントを拡張して、状態を保存し、モバイルアプリがそれらの更新に反応するようにする。

インメモリ状態を追加する

検証フローは「1回のリクエストで終わり」ではない。ライフサイクルがあるのだ:

  • 開始
  • 保留(サイレント認証/SMS)
  • 完了または不成立/期限切れ

もし状態をどこにも保存していなければ、バックエンドは何が起こったかを記憶していないことになる:

  • /callback ログデータしか取れない(あまり役に立たない)
  • アプリは現在の状況を確実に把握できない
  • デバッグが苦痛になる(「一度うまくいったのに、その後うまくいかなくなった...」)。

店舗があることで、真実が一元化される。

本番環境ではデータベース(Postgres/Redisなど)を使いますが、チュートリアルでは Map.

ステップ1: Map

Node.jsでは Map は、キーと値のペアをメモリに格納する簡単な方法である。

これを app.js:

// In-memory store for tutorial purposes:
// request_id -> verification state
const verificationStore = new Map();

リクエストボディの必須フィールドを検証するヘルパー関数を追加します。この関数を verificationStore と宣言した:

function requireFields(obj, fields) {
  for (const f of fields) {
    if (!obj || obj[f] == null || obj[f] === "") return f;
  }
  return null;
}

これは、最初に見つからないフィールドの名前を返す。 null すべてのフィールドが存在する場合

各エントリーのキーは request_id.

典型的なエントリーは次のようなものだ:

ステップ2:検証作成時の初期状態の保存

電話 verifyClient.newRequest(...)/verificationを受け取る。 request_id.

これが初期状態を保存するための完璧なキーなのだ。

内部 /verification エンドポイントを取得した直後に result:

verificationStore.set(result.requestId, {
  phone,
  status: "started",
  createdAt: new Date().toISOString(),
  updatedAt: new Date().toISOString(),
});

これでバックエンドは検証が開始されたことを "記憶 "する。

ステップ3:コールバックがイベントを受信したときに状態を更新する

コールバック(ウェブフック)は、Vonageがあなたのバックエンドに伝えるものです: "何かが変わった。これが新しいステータスだ。

ペイロードを記録するだけでなく、保存されている状態を更新する:

app.post("/callback", (req, res) => {
  const { request_id, status } = req.body || {};
  if (!request_id) return res.status(400).json({ error: "Missing request_id" });

  const current = verificationStore.get(request_id) || {
    phone: null,
    status: "unknown",
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    lastEvent: null,
  };

  const updated = {
    ...current,
    status: status || current.status,
    updatedAt: new Date().toISOString(),
    lastEvent: req.body,
  };

  verificationStore.set(request_id, updated);

  return res.status(200).json({ ok: true });
});

Webhookの配信は再試行される可能性があり、同じイベントを複数回受信する可能性があります。このようなストアの更新は当然冪等です。同じステータスを再度設定しても、何も壊れません。

ステップ4:モバイルアプリ用のステータス・エンドポイントを追加する

これで、アプリが現在の状態をチェックするために呼び出せるシンプルなエンドポイントを提供できる:

app.get("/status/:request_id", (req, res) => {
  const { request_id } = req.params;
  const entry = verificationStore.get(request_id);

  if (!entry) return res.status(404).json({ error: "Unknown request_id" });

  return res.json({
    request_id,
    status: entry.status,
    updated_at: entry.updatedAt,
  });
});

これは、アプリがやみくもに待つのではなく、1~2秒ごとに短時間ポーリングできるため、サイレント認証では特に便利だ。

ステップ5:追加 POST /next

について /next エンドポイントは、Vonage に現在のワークフロー・チャネルをスキップして次のチャネルに移るように指示する。私たちの場合、それはSilent Authをスキップし、すぐにSMSを送信することを意味します。

これはAndroidアプリで、Silent Authリクエストが失敗した場合(ネットワークが悪い、SDKエラーなど)に便利です。Vonageが自然にタイムアウトするのを20秒待つ代わりに、アプリは/nextを呼び出し、ユーザーはすぐにSMSを受け取ります。

app.post("/next", async (req, res) => {
  try {
    const missing = requireFields(req.body, ["requestId"]);
    if (missing) {
      return res.status(400).json({ error: `Field '${missing}' is required.` });
    }

    const { requestId } = req.body;

    const entry = verificationStore.get(requestId);
    if (!entry) {
      return res.status(404).json({ error: "Unknown request_id" });
    }

    console.log("Moving to next workflow (SMS) for:", requestId);

    // Call Vonage to move to next workflow
    const result = await verifyClient.nextWorkflow(requestId);
    console.log("Vonage nextWorkflow result:", result);

    // Update last event
    const updated = {
      ...entry,
      updatedAt: new Date().toISOString(),
      lastEvent: { source: "next_workflow", result },
    };
    verificationStore.set(requestId, updated);

    return res.status(200).json({ ok: true });
  } catch (error) {
    const status = error?.response?.status || 500;
    const details = error?.response?.data || error?.message;

    console.error("Error /next:", details);
    return res.status(status).json({
      error: "Failed to move workflow",
      details: typeof details === "string" ? details : undefined,
    });
  }
});

注: /nextが失敗しても致命的ではありません。VonageはSilent Authのタイムアウト後、自動的にSMSにフォールバックします。Androidアプリは、この通話が成功するかどうかに関係なく、SMS入力画面を表示する必要があります。