Webサイトでログイン機能を作るとき、一般的にはユーザー名とパスワードの組み合わせか、もしくはGoogleやFacebookなど外部のプラットフォームのログイン機能とOAuthの仕組みを利用してユーザー認証を行うことが多いと思います。
これらに代わる第三の方法にパスワードレスログインがあります。パスワードレスログインとはその名の通り、パスワードの入力を必要としないログイン方法のことです。例えば、ユーザーにパスワードを入力してもらう代わりに、EmailやSMS経由でワンタイムパスワードのような短い認証用のコードを送って本人確認を行う方法は、パスワードレスログインの一種です。
マジックリンクもまた、パスワードレスログインを実現するユニークな実装のひとつです。普段SlackやMediumといったサービスを利用している方なら、一度はこのマジックリンクを目にしたことがあるかもしれません。上記のような認証コードの代わりにマジックリンクと呼ばれるURLを送り、ユーザーがそのURLをクリックすると自動的にログインが完了します。まさにユーザーからするとまるで魔法のような仕組みです。
私もつい最近、このマジックリンクを実装して公開しました。実際の動きはこちら👇のようになります。
We recently created a passwordless login (aka magic link) on https://t.co/YJcixgGgra, so please give it a try! pic.twitter.com/2NRULFw8jG
— Tatsuya Oiwa (@tatsuyaoiw) June 24, 2020
ユーザーとシステムのおおまかなコミュニケーションフローは、以下のとおりです。
- ユーザー : マジックリンクの送信ボタンを押す。
- システム : ユーザーからリクエストを受け取ると、そのユーザー専用の認証用トークンを生成し、生成したトークンをマジックリンクのURLに含めてユーザーにEmailで送信する。
- ユーザー : Emailの受信箱からマジックリンクのURLをクリックする。
- システム : マジックリンクに含まれるトークンを抽出し検証、トークンが有効であればユーザーに認証済みのステータスを返す。
マジックリンクの実装
マジックリンクを実装においてコアとなるのは、#2のトークンの生成と、#4のトークンの検証の部分です。これらの実装方法は大きく二つのカテゴリ、ステートフルな実装とステートレスな実装に分けられます。
ステートフルな実装
ステートフルな実装の概要は次のとおりです。
- 認証用のトークンを任意の文字列(ランダム関数など)で生成する。
- 生成したトークンをサーバー側のデータストアに期限付きで格納する。
- 生成したトークンをマジックリンクに含めて送付する。
- トークンの照合および検証は、同じくサーバー側のデータストアに情報を問い合わせることで実現する。
ステートレスな実装
いっぽう、ステートレスな実装は次のようになります。
- 認証用のトークンにユーザー情報を含め、電子署名する。
- 生成したトークンをマジックリンクに含めて送付する。
- トークンの照合および検証は、電子署名の検証によって実現する。
両者の最も大きな違いは、ステートフルな実装ではサーバー側で別途データストアが必要である(サーバー側で各トークンの状態をもつ)のに対し、ステートレスな実装ではその必要がない点です。ステートレスな実装を実現するためのトークンの例として、JSON Web Token (JWT) があります。
(上記の他に、マジックリンクを含めたパスワードログインを提供するサードパーティのサービスを使う方法もあります。例えばAuth0ではマジックリンクの生成、メールの送信、トークンの検証を一括で行う機能を提供しています。)
メリットとデメリット
ステートフルな実装
- メリット: ロジックが簡単。トークン文字列の自由度が高い。必要に応じて発行済のトークンを取り消すことが可能
- デメリット: データストアを必要とするためシステムの複雑さが増す。同時に多数のリクエストを捌くケースにおいてはスケーラビリティの問題が発生する。
ステートレスな実装
- メリット: データストアを必要としないためシステムが簡略化できる。トークンの生成と検証を高速に行える。
- デメリット: トークンの実装ロジックがやや複雑になる。一度発行してしまったトークンはサーバー側で取り消すことが難しい。
Quartzのマジックリンク
Quartzでは、マジックリンク用のトークンにJWTとその署名アルゴリズムにECDSAを採用しました。JWTには様々な署名アルゴリズムを使用することできますが、非対称暗号で代表的なRSA(例えばAuth0の全てのトークンはデフォルトでRSA256が採用されている)と比較して、ECDSAでは処理スピードを犠牲にする代わりにキーサイズを短縮できるため、より短いトークンを生成することが可能です。
English version is here 👉 Implementing Passwordless Login with Magic Links