サウンドマインド
統合ログインサーバー
複数のサービスがひとつのアカウントを共有します。保護者と子ども端末はネットワーク事情が正反対のため、ログイン維持ポリシーから二つに分ける必要がありました。
- 役割
- バックエンド · 運用ダッシュボード
- 期間
- 2025.07 ~ 現在
- 使用技術
- Spring BootJava 17MariaDBRedisNext.js
改善結果
即時無効化
トークン再利用検知時にアカウントのトークンを全て失効
2種
ユーザータイプ別に分離したトークンポリシー
01課題
保護者は一般のスマートフォンから頻繁にアクセスするため、短命トークンを更新し続ける標準方式が適しています。しかし子ども端末は管理ポリシーによりネットワークが普段閉じており、更新リクエスト自体が頻繁に失敗します。同じポリシーを使うと子ども端末がたびたびログアウトされ、かといって全員に長命トークンを与えると、窃取された場合の被害が大きくなります。
02判断
タイプ別にポリシーを分けました。保護者は短命トークンとローテーション型リフレッシュトークンを使い、リフレッシュトークンが再利用された場合は窃取とみなして、そのアカウントのトークン系譜全体を即時無効化し記録を残します。子ども端末は更新なしの長期単一セッションで維持しつつ、セッション数を制限します。サービス間の認証イベントはリトライと保管キューを経て、管理者が復旧できるようにしました。
- 保護者: 短命トークン + ローテーション型リフレッシュ、再利用検知時は系譜全体の失効と監査記録
- 子ども端末: 長期単一セッション、同時セッション数の制限
- サービス間通知は指数バックオフでリトライし、失敗分を保管して手動での再処理が可能
- 変更されたサービスだけを選んでビルド・デプロイするスクリプトとモニタリングスタックを構成
03ログイン一つからアカウントプラットフォームへ
始まりはログインサーバーでしたが、自社サービスが一つずつ合流するにつれ、要求はアカウントプラットフォームへ育ちました。新しいサービスが入るたびにコードを直す方式では持たないため、合流・連携・伝播・整理をそれぞれ構造にしました。
一つのアカウント、複数のプロダクト
プロダクトは登録で合流し、出来事はWebhookで伝播し、失敗したイベントは消えずに保管されます
サービスの合流は登録で
新しいプロダクトはコード修正ではなく登録で合流します。クライアント識別子とAPIキー、許可IP、リダイレクト先をDBに登録すれば終わりで、CORSの許可リストもその登録から動的に作られます。登録がそのままポリシーです
家族連携の台帳
保護者と子どもの連携申請・承認・解除をSSOが台帳として管理します。どのプロダクトで連携しても同じ関係を全員が共有し、連携数には両側とも上限を設けます
認証イベントの伝播
連携や退会といった出来事は各サービスへWebhookで伝播します。冪等キーを付けて指数バックオフで3回再試行し、それでも失敗すれば保管箱に残して管理者が再送できます。イベントが静かに消えることはありません
アカウントのライフサイクル
休眠への移行、破棄予告と破棄、本人認証情報の保存期限をバッチが自動処理します。個人情報の整理が運用者の記憶ではなくスケジュールに掛かっています
運用ダッシュボード
会員照会、セッション強制終了、Webhook保管箱の再処理、監査ログまで専用ダッシュボードで扱います。障害対応がDBコンソールではなく画面で終わります
04結果
子ども端末がネットワーク事情でログアウトされる問題がなくなり、トークン窃取のシナリオでは再利用検知の時点でアカウント単位で即座に遮断されます。運用ダッシュボードからセッション一覧の確認と強制終了まで処理できます。