SMS二段階認証APIを自社サービスに組み込む方法
ミドリ: タツヤさん、最近うちのサービスで不正ログインが増えてきて……。パスワードだけの認証だと不安なんですけど、SMS認証って簡単に導入できるんですか?
タツヤ: いいところに気づいたね。IPAの調査によると、不正アクセスの約80%がパスワードリスト攻撃によるものなんだ。パスワードだけに頼るのはもう限界だよ。
ミドリ(confused): やっぱりそうですよね。でも、SMS認証をゼロから作るのって大変そうで……。
タツヤ: ゼロから作ると、SMS送信基盤の構築、ワンタイムパスワードの生成・検証ロジック、有効期限管理って膨大な開発コストがかかる。でも SMS認証API を使えば、最短30分で二段階認証を導入できるよ。
ミドリ: 30分!? それは気になります。
SMS認証の導入が求められる背景
タツヤ(nodding): まず、なぜSMS認証が必要なのか、リスクを整理しておこう。
| リスク | 具体的な被害例 |
|---|---|
| パスワードリスト攻撃 | 他サービスで漏洩したID/パスワードで不正ログインされる |
| フィッシング被害 | 偽サイトで入力されたパスワードが悪用される |
| ブルートフォース攻撃 | 単純なパスワードが総当たりで突破される |
ミドリ: どれもよく聞く話ですね……。
タツヤ: SMS認証を追加すれば、パスワードが漏洩しても電話番号を持っていなければログインできない。Googleの調査では、SMSベースの2FAでアカウント乗っ取りの96%を防止できるとされているよ。
ミドリ: 96%! それはもう導入しない理由がないですね。
SMS認証APIの仕組み
ミドリ(thinking): で、SMS認証APIって具体的にどう動くんですか?
タツヤ: 全体は4ステップで動くんだ。
- 認証リクエスト送信 — システムがAPIを呼ぶと、認証ページのURLが返されます
- ユーザーがアクセス — 返されたURLにユーザーがアクセスし、電話番号を入力します
- SMSコード入力 — ユーザーの携帯にSMSが届き、6桁のコードを入力します
- 認証結果確認 — システムがAPIで結果を確認し、認証完了を判定します
ミドリ: SMS送信もコード検証もAPIがやってくれるってことですか?
タツヤ(nodding): その通り。開発者はAPIを呼ぶだけで、セキュアなSMS認証をサービスに組み込める。自前で実装する必要は一切ないよ。
実装手順(3ステップ)
STEP 1: APIキーを取得する
タツヤ(nodding): まず、管理者から以下の2つを入手しよう。
- APIベースURL:
https://sms-ninshou-api.miyata-d23.workers.dev— 認証リクエストの送信先エンドポイントです - APIキー: 認証に使う秘密の文字列です。必ず環境変数で管理してください。ソースコードに直接書くのは厳禁です
ミドリ: APIキーは .env ファイルに入れておけばいいんですね。
タツヤ(smiling): そうだね。SMS_API_KEY=xxxxxx みたいに環境変数で管理するのがベストプラクティスだよ。
STEP 2: 認証リクエストを作成する
タツヤ: 次に、APIにPOSTリクエストを送って認証用URLを取得する。コードはこれだけ。
// Node.js / JavaScript の例
const response = await fetch(
'https://sms-ninshou-api.miyata-d23.workers.dev/api/v1/verifications',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SMS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
metadata: { user_id: 'ユーザーのID' },
}),
}
);
const data = await response.json();
console.log(data.verification_url);
// → "https://sms-ninshou.pages.dev/?t=abc123..."
// このURLをユーザーに提示します
ミドリ: metadataにユーザーIDを含めるのは何のためですか?
タツヤ: 認証結果とユーザーを紐付けるためだよ。「誰の認証が完了したか」を後で確認できるようにしておくんだ。
STEP 3: 認証結果を確認する
タツヤ: ユーザーがSMS認証を完了した後、結果をGETリクエストで確認する。
const result = await fetch(
`https://sms-ninshou-api.miyata-d23.workers.dev/api/v1/verifications/${data.request_id}`,
{
headers: { 'Authorization': `Bearer ${process.env.SMS_API_KEY}` },
}
);
const status = await result.json();
if (status.status === 'verified') {
console.log('認証完了!ログインを許可します');
}
ミドリ: POST → ユーザー認証 → GET の3ステップだけで完成するんですね。思ったよりずっと簡単だ!
タツヤ: でしょ? これがAPI利用の最大のメリットだよ。
テストモードで動作確認する
ミドリ(confused): でも開発中にSMSが毎回飛ぶと、料金が心配です……。
タツヤ: 大丈夫。テストモードがあるから、本番のSMSを送信せずに動作確認できるよ。
| 項目 | 値 |
|---|---|
| テスト電話番号 | 09012345678 |
| テスト認証コード | 123456 |
ミドリ: この電話番号を使うとSMSが送信されないんですね?
タツヤ(nodding): その通り。コード 123456 で認証完了として扱われるから、送信料金を気にせず何度でも開発・デバッグできる。本番リリース前の結合テストにも活用してね。
二段階認証の組み込みパターン
ミドリ: 実際のサービスに組み込むとき、どんなパターンがありますか?
タツヤ: 代表的な2つのパターンを紹介するよ。
パターン1: リダイレクト方式(最もシンプル)
タツヤ: ログイン後にSMS認証ページへリダイレクトする方式。実装が最もシンプルで、小規模サービスに適しているよ。
// ログイン処理
app.post('/login', async (req, res) => {
// 通常のパスワード認証
const user = await authenticate(req.body.email, req.body.password);
if (!user) return res.status(401).json({ error: 'ログイン失敗' });
// SMS認証リクエスト作成
const smsRes = await fetch(
'https://sms-ninshou-api.miyata-d23.workers.dev/api/v1/verifications',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SMS_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ metadata: { user_id: user.id } }),
}
);
const smsData = await smsRes.json();
// ユーザーをSMS認証ページへリダイレクト
res.redirect(smsData.verification_url);
});
パターン2: ポップアップ方式(UX重視)
タツヤ: メイン画面を維持したまま、別ウィンドウでSMS認証を行う方式。ユーザー体験を重視するサービスに向いているよ。
// フロントエンドで認証ウィンドウを開く
window.open(verificationUrl, '_blank', 'width=400,height=600');
// 3秒ごとに認証完了を確認
const interval = setInterval(async () => {
const res = await fetch(`/api/check/${requestId}`);
const data = await res.json();
if (data.status === 'verified') {
clearInterval(interval);
window.location.href = '/dashboard';
}
}, 3000);
ミドリ: リダイレクト方式がシンプルで、まずはこっちで試してみます!
Python・PHPでの実装例
ミドリ: うちのチームにはPythonやPHPを使っているメンバーもいるんですが……。
タツヤ: もちろん対応できるよ。それぞれのコード例を載せておくね。
Python
import requests
res = requests.post(
"https://sms-ninshou-api.miyata-d23.workers.dev/api/v1/verifications",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={"metadata": {"user_id": "12345"}},
)
data = res.json()
print(f"認証URL: {data['verification_url']}")
PHP
$ch = curl_init("https://sms-ninshou-api.miyata-d23.workers.dev/api/v1/verifications");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("SMS_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["metadata" => ["user_id" => "12345"]]),
]);
$data = json_decode(curl_exec($ch), true);
echo "認証URL: " . $data["verification_url"];
ミドリ(confused): どの言語でもほぼ同じ構造なんですね。コピペで使えそうです!
認証画面の特徴
ミドリ: ユーザーが実際に見る認証画面って、どんな感じですか?
タツヤ: モバイルファーストで設計されていて、かなり使いやすいよ。
- QRコード対応 — PCからアクセスした場合、QRコードが表示されます。スマホで読み取るだけで認証を開始できます
- レスポンシブデザイン — iPhone・Android両対応で、スマホから直接アクセスした場合は電話番号入力画面が表示されます
- 6桁OTP入力UI — 1マスずつ入力する見やすいUIで、入力ミスを防止します
- WebOTP対応 — iOSのWebOTPに対応しており、SMSコードの自動入力をサポートします。ユーザーが手動でコードを入力する手間を省けます
ミドリ: WebOTP対応はいいですね! ユーザーが手打ちしなくていいのは離脱防止につながりそうです。
導入効果
タツヤ: 実際の導入効果をまとめるとこんな感じだよ。
| 指標 | 効果 |
|---|---|
| 不正ログイン防止率 | 96%のアカウント乗っ取りを防止(Google調査) |
| 導入工数 | 最短30分〜半日(API利用の場合) |
| 運用コスト | 1日10通まで無料、超過分は1通約4.5円 |
| ユーザー離脱率 | SMS認証の完了率は平均85%以上 |
ミドリ: 自前で構築すると数週間かかるところが、半日で済むのは大きいですね。
タツヤ: そうだね。Twilioなどのサービス契約・送信ロジック・OTP管理を含めると数週間は覚悟が必要だけど、APIを使えばこの工数を大幅に圧縮できる。
よくある質問
ミドリ: 導入前に気になることをいくつか聞いてもいいですか?
タツヤ: もちろん。よくある質問をまとめて答えるよ。
ミドリ: 料金はかかりますか?
タツヤ(smiling): 1日10通まで無料だよ。超過分は1通あたり約4.5円で利用できる。
ミドリ: 同じ電話番号で何回も認証できますか?
タツヤ: いや、1つの電話番号につき1回のみ。本人確認の一意性を保証するための仕様だね。
ミドリ: 海外の電話番号は使えますか?
タツヤ: 現在は日本(+81)のみ対応しているよ。海外番号の追加は設定変更で対応可能だ。
ミドリ: セキュリティは大丈夫ですか?
タツヤ: 電話番号はハッシュ化して保存されるから安心して。生の電話番号はAPIレスポンスに含まれない。通信もすべてHTTPSで暗号化されているよ。
まとめ
タツヤ: 今日の内容をまとめると、SMS二段階認証の導入は3つのAPIコールだけで完了する。
POST /verificationsで認証URLを取得する- ユーザーが認証URLでSMS認証を行う
GET /verifications/:idで結果を確認する
ミドリ: テストモード(電話番号 09012345678 / コード 123456)を使えば、SMS送信なしで今すぐ開発を始められるんですよね。
タツヤ(nodding): その通り。JavaScript・Python・PHPのどの言語でも、コピペで実装可能だよ。まずはテストモードで試してみて!
次のステップ
タツヤ: じゃあ次にやることを整理しておこう。
- テストモードで試す — まずはテスト用の電話番号で動作を確認してみてください
- APIリファレンス — 詳しい仕様は GitHub リポジトリ を参照してください
- 導入相談 — 本番環境への組み込みや大量送信プランについては、Shimanto AI Solutionsまでお気軽にお問い合わせください
ミドリ(smiling): さっそくテストモードで試してみます! ありがとうございました!