ユーザー移行
Logto は、他のアイデンティティシステムから既存ユーザーを一括またはジャストインタイムで移行することをサポートしています。このガイドでは、Management API を使用してユーザーを一括インポートする方法と、移行前に考慮すべき点について説明します。
移行戦略を選択する
| 戦略 | 選択するタイミング | 動作方法 |
|---|---|---|
| 一括移行 | ユーザーレコードとパスワードハッシュを Logto がサポートする形式でエクスポートできる場合。 | このガイドに従い、Management API を通じてカットオーバー前にユーザーをインポートします。 |
| ジャストインタイム移行 | 既存システムでパスワードの検証が必要、互換性のあるパスワードハッシュをエクスポートできない、またはアクティブユーザーを段階的に移行したい場合。 | Post first-factor verification Action を設定します。ユーザーが初めてパスワードでサインインする際、Logto は Action を通じて認証情報を検証し、ユーザーを作成または更新し、新しいローカルパスワードハッシュを保存します。 |
ジャストインタイム移行では、ユーザーが移行されるまでレガシー認証 (Authentication) サービスがサインインリクエスト経路に残ります。高速で信頼性の高い HTTPS エンドポイントを使用し、移行期間中は利用可能な状態を維持してください。
ユーザースキーマ
始める前に、Logto の ユーザースキーマ を確認しましょう。ユーザースキーマには次の 3 つの部分があります:
- 基本データ:ユーザープロファイルの基本情報で、既存のユーザープロファイルのデータとマッチさせることができます。
- カスタムデータ:追加のユーザー情報を保存します。基本データにマッチできないファイルなどを保存するのに利用できます。
- ソーシャルアイデンティティ:ソーシャルサインインから取得したユーザー情報を保存します。
既存のユーザープロファイルから 基本データ および カスタムデータ へのマッピングを作成できます。ソーシャルサインインの場合は、ソーシャルアイデンティティのインポートに追加の手順が必要です。詳細は Link social identity to user の API を参照してください。
既存のユーザー ID を保持する
デフォルトでは、Logto は Management API を通じて作成された各ユーザーにランダムな ID を生成します。アプリケーションが既に以前のアイデンティティプロバイダーのユーザー ID を保持している場合、create user リクエストボディでオプションの id を渡すことで、それらを保持できます。これにより、古い ID と新しい ID のマッピングテーブルを維持する必要がなくなります。
ID は 1 文字から 128 文字までで、英字、数字、_ - . @ : + = | を含めることができます。これにより、auth0|5f7c8ec7c33c6c004bbafe82、google-oauth2|103547991597142817347、UUID、user_01H8MZ2QK3V4X5Y6Z7、メールアドレスなどの一般的な形式をカバーします。URL パスで無効な文字(空白、/、?、#、%、\)は /api/users/{userId} で使用されるため 400 で拒否されます。ID が既に使用されている場合、リクエストは 422 user.id_already_in_use で失敗します。
{
"id": "auth0|5f7c8ec7c33c6c004bbafe82",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Bcrypt",
"passwordDigest": "$2b$10$..."
}
カスタムユーザー ID はセルフホスト型 Logto のみサポートされています。Logto Cloud では、id を含むリクエストは 501 request.feature_not_supported で拒否されます。これはユーザー ID がテナント間で共有されているためです。
パスワードハッシュ化
Logto はユーザーのパスワードを Argon2 でハッシュ化しますが、移行の利便性のために MD5、SHA1、SHA256、Bcrypt など他のアルゴリズムもサポートしています。これらのアルゴリズムは安全ではないと見なされており、該当するパスワードハッシュはユーザーが初めてサインインに成功した際に Argon2 へ移行されます。
他のハッシュアルゴリズムやソルトを使用している場合は、passwordAlgorithm を Legacy に設定できます。これにより、Node.js でサポートされている任意のハッシュアルゴリズムを使用できます。サポートされているアルゴリズムの一覧は Node.js crypto ドキュメント を参照してください。この場合、passwordDigest はハッシュアルゴリズムやその他のパラメータを含む JSON 文字列となります。
一般的な Legacy 形式
JSON 文字列の形式は次の通りです:
["hash_algorithm", ["argument1", "argument2", ...], "expected_hashed_value"]
引数内で実際のパスワード値のプレースホルダーとして @ を使用できます。
例えば、ソルト付き SHA256 を使用している場合、次の形式でパスワードを保存できます:
["sha256", ["salt123", "@"], "c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e"]
これは次のコードと同等です:
const hash = crypto.createHash('sha256');
// 'salt123' + 'password123' をハッシュ化
hash.update('salt123' + 'password123');
const expectedHashedValue = hash.digest('hex');
PBKDF2 サポート
Logto は PBKDF2 もサポートしています。
PBKDF2 でハッシュ化されたパスワードを移行するには、passwordAlgorithm を Legacy に設定し、passwordDigest を次のようにフォーマットします:
["pbkdf2", ["salt", "1000", "20", "sha512", "@"], "expected_hashed_value"]
各パラメータの意味は以下の通りです:
salt:元のハッシュ化で使用したソルト値iterations:イテレーション回数(例:"1000")keylen:導出キーのバイト長(例:"20")digest:使用したハッシュ関数(例:"sha512"、"sha256"、"sha1")@:実際のパスワード値のプレースホルダーexpected_hashed_value:16進文字列で表した期待されるハッシュ結果
移行ペイロード例:
{
"username": "john_doe",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Legacy",
"passwordDigest": "[\"pbkdf2\", [\"mySalt123\", \"1000\", \"20\", \"sha512\", \"@\"], \"c465f66c6ac481a7a17e9ed5b4e2e7e7288d892f12bf1c95c140901e9a70436e\"]"
}
Firebase scrypt サポート
Logto は Firebase Authentication で使用される修正版 scrypt アルゴリズム もサポートしています。passwordAlgorithm を Legacy に設定し、passwordDigest を次のようにフォーマットします:
[
"firebase-scrypt",
["salt", "signer_key", "salt_separator", "rounds", "mem_cost", "@"],
"expected_hashed_value"
]
各パラメータの意味は以下の通りです:
salt:firebase auth:exportから取得したユーザーのsaltsigner_key,salt_separator,rounds,mem_cost:Firebase コンソールの Authentication > Users > ⋮ > Password hash parameters で確認できるプロジェクトのパスワードハッシュパラメータ@:実際のパスワード値のプレースホルダーexpected_hashed_value:エクスポートしたユーザーのpasswordHash(標準 base64)。Firebase Admin SDK でユーザーを取得した場合は、URL セーフ base64(-,_)を標準 base64(+,/)に変換してください。
passwordDigest は 256 文字までに制限されているため、スペースのないコンパクトな JSON でシリアライズしてください(例:JSON.stringify を使用)。
scrypt 以外のハッシュで Firebase にインポートされ、サインインしていないユーザーは、エクスポート時に passwordHash と salt が空になります。元のハッシュが残っていればそれでインポートし、なければパスワードリセットを依頼してください。
移行ペイロード例:
{
"username": "john_doe",
"primaryEmail": "john.doe@example.com",
"passwordAlgorithm": "Legacy",
"passwordDigest": "[\"firebase-scrypt\",[\"42xEC+ixf3L2lw==\",\"jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA==\",\"Bw==\",\"8\",\"14\",\"@\"],\"lSrfV15cpx95/sZS2W9c9Kp6i/LVgQNDNC/qzrCnh1SAyZvqmZqAjTdn3aoItz+VHjoZilo78198JAdRuid5lQ==\"]"
}
移行手順
-
ユーザーデータの準備
まず既存プラットフォームからユーザーデータをエクスポートし、ユーザー情報を Logto のユーザースキーマにマッピングします。マッピング済みデータは JSON 形式で準備することを推奨します。ユーザーデータの例は以下の通りです:[{"username": "user1","passwordDigest": "password-encrypted","passwordAlgorithm": "SHA256"},{"username": "user2","passwordDigest": "password-encrypted","passwordAlgorithm": "SHA256"}] -
Logto テナントの作成
Logto でテナントをセットアップします。Logto Cloud または Logto OSS のいずれかを利用できます。まだセットアップしていない場合は、Logto cloud のセットアップ ガイドを参照してください。 -
Management API の接続設定
Management API を使用してユーザーデータをインポートします。開発環境での接続方法は Management API を参照してください。 -
ユーザーデータのインポート
ユーザーデータを 1 件ずつインポートするスクリプトを用意することを推奨します。create user API を呼び出してユーザーデータをインポートします。スクリプト例は以下の通りです:const users = require('./users.json');const importUsers = async () => {for (const user of users) {try {await fetch('https://[tenant_id].logto.app/api/users', {method: 'POST',headers: {'Content-Type': 'application/json',Authorization: 'Bearer [your-access-token]',},body: JSON.stringify(user),});// レートリミット回避のため少し待機await new Promise((resolve) => setTimeout(resolve, 200));} catch (error) {console.error(`ユーザー ${user.username} のインポートに失敗しました: ${error.message}`);}}};importUsers();
API エンドポイントにはレートリミットがあるため、各リクエストの間に待機時間を設けてください。詳細は レートリミット ページをご確認ください。
大量のユーザーデータ(10 万件以上)がある場合は、お問い合わせください 。レートリミットの引き上げが可能です。
関連リソース
既存のユーザーデータベースを Logto へ移行するための一般的なガイドライン