マジックリンクでパスワードレスログインを実現する

June 23, 2020

Webサイトでログイン機能を作るとき、一般的にはユーザー名とパスワードの組み合わせか、もしくはGoogleやFacebookなど外部のプラットフォームのログイン機能とOAuthの仕組みを利用してユーザー認証を行うことが多いと思います。

これらに代わる第三の方法にパスワードレスログインがあります。パスワードレスログインとはその名の通り、パスワードの入力を必要としないログイン方法のことです。例えば、ユーザーにパスワードを入力してもらう代わりに、EmailやSMS経由でワンタイムパスワードのような短い認証用のコードを送って本人確認を行う方法は、パスワードレスログインの一種です。

マジックリンクもまた、パスワードレスログインを実現するユニークな実装のひとつです。普段SlackやMediumといったサービスを利用している方なら、一度はこのマジックリンクを目にしたことがあるかもしれません。上記のような認証コードの代わりにマジックリンクと呼ばれるURLを送り、ユーザーがそのURLをクリックすると自動的にログインが完了します。まさにユーザーからするとまるで魔法のような仕組みです。

私もつい最近、このマジックリンクを実装して公開しました。実際の動きはこちら👇のようになります。

ユーザーとシステムのおおまかなコミュニケーションフローは、以下のとおりです。

  1. ユーザー : マジックリンクの送信ボタンを押す。
  2. システム : ユーザーからリクエストを受け取ると、そのユーザー専用の認証用トークンを生成し、生成したトークンをマジックリンクのURLに含めてユーザーにEmailで送信する。
  3. ユーザー : Emailの受信箱からマジックリンクのURLをクリックする。
  4. システム : マジックリンクに含まれるトークンを抽出し検証、トークンが有効であればユーザーに認証済みのステータスを返す。

マジックリンクの実装

マジックリンクを実装においてコアとなるのは、#2のトークンの生成と、#4のトークンの検証の部分です。これらの実装方法は大きく二つのカテゴリ、ステートフルな実装ステートレスな実装に分けられます。

ステートフルな実装

ステートフルな実装の概要は次のとおりです。

  1. 認証用のトークンを任意の文字列(ランダム関数など)で生成する。
  2. 生成したトークンをサーバー側のデータストアに期限付きで格納する。
  3. 生成したトークンをマジックリンクに含めて送付する。
  4. トークンの照合および検証は、同じくサーバー側のデータストアに情報を問い合わせることで実現する。

ステートレスな実装

いっぽう、ステートレスな実装は次のようになります。

  1. 認証用のトークンにユーザー情報を含め、電子署名する。
  2. 生成したトークンをマジックリンクに含めて送付する。
  3. トークンの照合および検証は、電子署名の検証によって実現する。

両者の最も大きな違いは、ステートフルな実装ではサーバー側で別途データストアが必要である(サーバー側で各トークンの状態をもつ)のに対し、ステートレスな実装ではその必要がない点です。ステートレスな実装を実現するためのトークンの例として、JSON Web Token (JWT) があります。

(上記の他に、マジックリンクを含めたパスワードログインを提供するサードパーティのサービスを使う方法もあります。例えばAuth0ではマジックリンクの生成、メールの送信、トークンの検証を一括で行う機能を提供しています。)

メリットとデメリット

ステートフルな実装

  • メリット: ロジックが簡単。トークン文字列の自由度が高い。必要に応じて発行済のトークンを取り消すことが可能
  • デメリット: データストアを必要とするためシステムの複雑さが増す。同時に多数のリクエストを捌くケースにおいてはスケーラビリティの問題が発生する。

ステートレスな実装

  • メリット: データストアを必要としないためシステムが簡略化できる。トークンの生成と検証を高速に行える。
  • デメリット: トークンの実装ロジックがやや複雑になる。一度発行してしまったトークンはサーバー側で取り消すことが難しい。

Quartzのマジックリンク

Quartzでは、マジックリンク用のトークンにJWTとその署名アルゴリズムにECDSAを採用しました。JWTには様々な署名アルゴリズムを使用することできますが、非対称暗号で代表的なRSA(例えばAuth0の全てのトークンはデフォルトでRSA256が採用されている)と比較して、ECDSAでは処理スピードを犠牲にする代わりにキーサイズを短縮できるため、より短いトークンを生成することが可能です。

English version is here 👉 Implementing Passwordless Login with Magic Links


Hey, I’m Tatsuya. I’m a Japanese software engineer living in Toronto. You can also find me on Twitter.