外部IdP UserInfo透過取得API 要件定義書
外部 IdP からのユーザー情報取得 API の挙動と契約、最小限ユーザー情報の取得方針。
1. 概要
EcAuthに「外部IdPのUserInfo情報を透過的に取得するAPI」を追加します。Auth0のManagement APIと異なり、より簡潔なインターフェースで、EcAuthのsubjectと外部IdPのprovider nameを指定するだけで、外部IdPのユーザー情報を取得できるようにします。
2. 背景と目的
2.1 現状の課題
- PR #119: 現在のUserInfo endpointは、EcAuth内部のsubjectのみを返却(個人情報保護法準拠)
- 制約: EC-CUBEなどのクライアントアプリが外部IdP(Google、LINE等)のユーザー詳細情報を取得できない
- ユースケース: プロフィール画面でのユーザー情報表示、メールアドレス確認など
2.2 Auth0との比較
Auth0の方式:
# 1. Management API トークン取得
curl -X POST "https://{domain}.auth0.com/oauth/token" \
-d '{"grant_type":"client_credentials",...}'
# 2. ユーザー情報取得
curl -H "Authorization: Bearer {token}" \
"https://{domain}.auth0.com/api/v2/users/{user_id}"EcAuthの提案方式 (よりシンプル):
# 1回のリクエストで完結
curl -H "Authorization: Bearer {access_token}" \
"https://ecauth.example.com/v1/api/external-userinfo?provider=google-oauth2"3. 機能要件
3.1 エンドポイント仕様
エンドポイント
GET /v1/api/external-userinfo
リクエストパラメータ
| パラメータ | 型 | 必須 | 説明 | 例 |
|---|---|---|---|---|
provider |
string | はい | 外部IdPのprovider name(open_id_provider.name) | google-oauth2, federate-oauth2 |
リクエストヘッダー
Authorization: Bearer {access_token}
レスポンス(成功時: 200 OK)
{
"sub": "external-idp-subject-123",
"email": "user@example.com",
"email_verified": true,
"name": "山田太郎",
"given_name": "太郎",
"family_name": "山田",
"picture": "https://example.com/avatar.jpg",
"locale": "ja",
"provider": "google-oauth2"
}※外部IdPから取得した生のクレーム情報をそのまま返却
エラーレスポンス
401 Unauthorized - アクセストークンが無効
{
"error": "invalid_token",
"error_description": "アクセストークンが無効または期限切れです。"
}404 Not Found - 指定されたproviderが存在しない、または外部IdP連携がない
{
"error": "provider_not_found",
"error_description": "指定されたproviderが見つかりません。"
}500 Internal Server Error - 外部IdPへのリクエスト失敗
{
"error": "external_idp_error",
"error_description": "外部IdPからユーザー情報を取得できませんでした。"
}4. 技術設計
4.1 処理フロー
1. クライアント → EcAuth /v1/api/external-userinfo?provider=google-oauth2
├─ Authorization: Bearer {access_token}
2. EcAuth: アクセストークン検証
├─ TokenService.ValidateAccessTokenAsync()
├─ EcAuthUser.Subject を取得
3. EcAuth: 外部IdPマッピング取得
├─ ExternalIdpMapping テーブルから検索
│ WHERE ecauth_subject = {subject}
│ AND external_provider = {provider}
├─ external_subject を取得
4. EcAuth: OpenIdProvider設定取得
├─ OpenIdProvider テーブルから検索
│ WHERE name = {provider}
├─ userinfo_endpoint を取得
5. EcAuth → 外部IdP UserInfo endpoint
├─ 外部IdPのアクセストークンを取得(後述)
├─ GET {userinfo_endpoint}
│ Authorization: Bearer {external_access_token}
6. 外部IdP → EcAuth: ユーザー情報返却
7. EcAuth → クライアント: ユーザー情報転送
4.2 外部IdPアクセストークンの取得方法
重要な課題: 外部IdPのアクセストークンは現在保存していない
オプション1: アクセストークンの保存(推奨)
新規テーブル: external_idp_token
CREATE TABLE external_idp_token (
id INT IDENTITY(1,1) PRIMARY KEY,
ecauth_subject NVARCHAR(255) NOT NULL,
external_provider NVARCHAR(100) NOT NULL,
access_token NVARCHAR(2048) NOT NULL,
refresh_token NVARCHAR(2048),
expires_at DATETIMEOFFSET NOT NULL,
created_at DATETIMEOFFSET NOT NULL DEFAULT SYSDATETIMEOFFSET(),
updated_at DATETIMEOFFSET NOT NULL DEFAULT SYSDATETIMEOFFSET(),
CONSTRAINT FK_ExternalIdpToken_EcAuthUser FOREIGN KEY (ecauth_subject) REFERENCES ecauth_user(subject),
INDEX IX_ExternalIdpToken_Subject_Provider (ecauth_subject, external_provider)
);保存タイミング: AuthorizationCallbackController::ExternalCallback()でJITプロビジョニング時
利点:
- リアルタイムでユーザー情報を取得可能
- トークン更新(リフレッシュトークン)に対応可能
課題:
- 個人情報保護法の観点から検討が必要(アクセストークン自体には個人情報が含まれる可能性)
- トークン有効期限管理が必要
オプション2: プロキシ方式(代替案)
クライアントが外部IdPに直接アクセスする方式(EcAuthは仲介のみ)
利点:
- EcAuth側でトークン保存不要
- 個人情報保護法のリスクが低い
課題:
- クライアント側の実装が複雑化
- セキュリティリスク(クライアントが外部IdP情報を知る必要がある)
5. 個人情報保護法への準拠
5.1 法的考察
現在の設計(PR #119):
- UserInfo endpoint: subjectのみ返却
- 個人情報を保存しない設計
新API追加の影響:
- 外部IdPトークンの保存: アクセストークン自体には個人情報は含まれない(通常はランダム文字列)
- ユーザー情報の転送: EcAuthは中継のみ(キャッシュしない)
- 法的判断: アクセストークンは「個人情報」には該当しない可能性が高い
5.2 推奨アプローチ
トークンの一時保存のみ
- 有効期限付き(外部IdPに準拠)
- 期限切れ後は自動削除
ユーザー情報のキャッシュなし
- 外部IdPから取得した情報はそのまま転送
- EcAuth側でのDB保存なし
プライバシーポリシーでの明記
- 外部IdPアクセストークンを一時保存することを明記
- ユーザーの同意取得
6. 実装計画
6.1 実装ステップ
Phase 1: 基盤整備
ExternalIdpTokenモデル作成
- エンティティクラス
- DBマイグレーション
IExternalIdpTokenServiceインターフェース作成
- SaveTokenAsync()
- GetTokenAsync()
- RefreshTokenAsync()
- CleanupExpiredTokensAsync()
Phase 2: トークン保存機能
- AuthorizationCallbackController拡張
- JITプロビジョニング時にトークン保存
- リフレッシュトークンの保存
Phase 3: 透過取得API実装
ExternalUserInfoController作成
- GET /v1/api/external-userinfo
- パラメータ検証
- 外部IdP UserInfo取得ロジック
IExternalUserInfoServiceインターフェース作成
- GetExternalUserInfoAsync()
- 外部IdPへのHTTPリクエスト処理
Phase 4: テストと検証
ユニットテスト作成
- ExternalIdpTokenServiceTests
- ExternalUserInfoControllerTests
統合テスト作成
- 外部IdP連携テスト
- トークン更新テスト
E2Eテスト拡張
- フェデレーション認証 + 外部UserInfo取得
7. セキュリティ考慮事項
7.1 トークン管理
- 暗号化: 外部IdPトークンのDB保存時に暗号化を検討
- 有効期限管理: 期限切れトークンの自動削除
- リフレッシュトークン: 安全な更新メカニズム
7.2 アクセス制御
- Bearer Token認証: EcAuthのアクセストークン必須
- マルチテナント: Organization単位でのデータ分離
- レート制限: DoS攻撃防止のための制限検討
8. マイルストーン
MVP(Minimum Viable Product)
Phase 2
Phase 3(オプション)
9. 関連ドキュメント
- user-management-architecture.md
- requirements.md
- PR #119: UserInfoエンドポイント実装
- Issue #23: user-management-architecture の実装
10. 実装後の利用例
// EC-CUBEプラグインでの利用例
async function fetchExternalUserInfo(accessToken: string, provider: string) {
const response = await fetch(
`https://ecauth.example.com/v1/api/external-userinfo?provider=${provider}`,
{
headers: {
'Authorization': `Bearer ${accessToken}`
}
}
);
if (!response.ok) {
throw new Error('Failed to fetch external user info');
}
const userInfo = await response.json();
// ユーザープロフィール画面に表示
displayUserProfile({
name: userInfo.name,
email: userInfo.email,
avatar: userInfo.picture
});
}以上の要件定義に基づいて実装を進めることで、Auth0より簡潔で使いやすい外部IdP UserInfo透過取得APIを提供できます。