着信認証APIの実装方法(Node.js編) — pauth-js SDK入門
公開日: 2026-03-02
このチュートリアルでは、pauth.me着信認証APIをNode.jsアプリケーションに組み込む方法を解説します。公式SDK pauth-js を使えば、わずか数行のコードで電話番号認証フローを実装できます。
前提条件
- Node.js 18以上
- npm または yarn
- pauth.me のアカウント(APIキー取得のため)
アカウントは無料で作成できます。サンドボックスAPIキー(test_ プレフィックス)があれば、実際の電話を使わずに動作確認できます。
インストール
npm install pauth-js
TypeScriptを使う場合も同パッケージに型定義が含まれているため、追加インストールは不要です。
APIキーの設定
APIキーはソースコードに直書きせず、環境変数で管理します。
# .env ファイルに記述
PAUTH_API_KEY=test_your-api-key-here
npm install dotenv
認証フロー実装(基本)
verify() メソッドを使うと、認証フロー全体(トークン取得 → 着信待機 → PIN照合)を1ステップで実行できます。
require('dotenv').config();
const { PauthClient } = require('pauth-js');
const client = new PauthClient({ apiKey: process.env.PAUTH_API_KEY });
async function authenticateUser(phoneNumber) {
// 電話番号は国際形式(+81始まり)で指定
const result = await client.verify(phoneNumber);
console.log('認証成功:', result.callerNumber);
return result;
}
authenticateUser('+819012345678').catch(console.error);
電話番号の形式: 日本の場合、0312345678 → +81312345678(先頭の0を除いて+81を付与)です。
サンドボックス動作: APIキーが test_ で始まる場合、サンドボックスモードで動作します。約2秒後に自動でPIN 1234 が返るため、実際に電話しなくても認証フローを確認できます。
ステップ分割フロー(entry / apply)
ユーザーに「この番号に電話してください」と表示してから確認するUIを実装する場合は、entry() と apply() を分けて使います。
require('dotenv').config();
const { PauthClient } = require('pauth-js');
const client = new PauthClient({ apiKey: process.env.PAUTH_API_KEY });
// Step 1: 認証セッション開始 — ユーザーに発信先番号を提示
async function startAuth(phoneNumber) {
const session = await client.entry(phoneNumber);
// session.callerd_number: ユーザーが電話すべき番号
// session.expires_in: 有効期限(秒)
console.log('この番号に電話してください:', session.callerd_number);
return session;
}
// Step 2: ユーザーが電話 → PINを受け取って照合
async function verifyPin(phoneNumber, pin) {
const isValid = await client.apply(phoneNumber, pin);
if (isValid) {
console.log('認証成功!');
} else {
console.log('PINが一致しません。');
}
return isValid;
}
Expressでの実装例(フルコード)
require('dotenv').config();
const express = require('express');
const { PauthClient, RateLimitError, ConflictError } = require('pauth-js');
const app = express();
app.use(express.json());
const client = new PauthClient({ apiKey: process.env.PAUTH_API_KEY });
// 電話番号フォーマット変換(日本国内形式 → 国際形式)
function toInternational(phone) {
return phone.replace(/^0/, '+81');
}
// POST /auth/start — 認証セッション開始
app.post('/auth/start', async (req, res) => {
const { phone } = req.body;
if (!phone) {
return res.status(400).json({ error: '電話番号が必要です' });
}
try {
const session = await client.entry(toInternational(phone));
res.json({
callNumber: session.callerd_number,
expiresIn: session.expires_in,
message: `${session.callerd_number} に電話してください(1コールで切ってOK)`,
});
} catch (err) {
if (err instanceof ConflictError) {
return res.status(409).json({ error: 'この番号で認証が進行中です。しばらく待ってから再試行してください。' });
}
if (err instanceof RateLimitError) {
return res.status(429).json({ error: 'リクエストが多すぎます', retryAfter: err.retryAfter });
}
console.error('認証開始エラー:', err);
res.status(500).json({ error: '認証を開始できませんでした' });
}
});
// POST /auth/verify — PIN照合して認証完了
app.post('/auth/verify', async (req, res) => {
const { phone, pin } = req.body;
if (!phone || !pin) {
return res.status(400).json({ error: '電話番号とPINが必要です' });
}
try {
const isValid = await client.apply(toInternational(phone), pin);
if (isValid) {
res.json({ success: true, message: '認証完了' });
} else {
res.status(401).json({ success: false, error: 'PINが一致しません' });
}
} catch (err) {
console.error('PIN照合エラー:', err);
res.status(500).json({ error: '認証確認に失敗しました' });
}
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
エラーハンドリング
| エラークラス | 発生条件 | 対応方法 |
|---|---|---|
AuthenticationError | 無効・期限切れのAPIキー(401) | APIキーを確認してください |
ConflictError | 同一番号で認証が既に進行中(409) | ユーザーに待機を促す |
RateLimitError | レート制限超過(429) | err.retryAfter 秒後にリトライ |
TimeoutError | PIN待機タイムアウト | ユーザーに再試行を促す |
const {
PauthClient,
AuthenticationError,
ConflictError,
RateLimitError,
TimeoutError,
} = require('pauth-js');
try {
const result = await client.verify('+819012345678');
} catch (err) {
if (err instanceof AuthenticationError) {
console.error('APIキーが無効です。環境変数PAUTH_API_KEYを確認してください。');
} else if (err instanceof RateLimitError) {
console.error(`レート制限。${err.retryAfter}秒後にリトライしてください。`);
} else if (err instanceof TimeoutError) {
console.error('タイムアウト。ユーザーが電話しなかった可能性があります。');
} else {
throw err;
}
}
本番環境の注意点
- APIキーの安全な管理
- 本番用APIキー(
live_プレフィックス)はGitリポジトリに含めないでください。.envを.gitignoreに追加することを忘れずに。 - レート制限への対応
- pauth.meにはAPIのレート制限があります。
RateLimitErrorを適切にキャッチし、err.retryAfter秒後に自動リトライするか、ユーザーに待機を案内する実装を推奨します。 - サンドボックス → 本番の切り替え
- APIキーを
test_からlive_に変更するだけで本番環境に切り替わります。コードの変更は不要です。
まとめ
pauth-js SDKを使えば、以下のシンプルなステップで着信認証をNode.jsアプリに組み込めます。
npm install pauth-jsでインストールnew PauthClient({ apiKey })でクライアント初期化client.verify(phoneNumber)またはentry() → apply(phoneNumber, pin)で認証フロー実行- エラーハンドリングで
ConflictError/RateLimitErrorに対応
関連ページ: SMS認証 vs 着信認証 比較ページ | 料金プラン | 予約システムでの活用