Part2-実践編TECHアドベントカレンダーこんにちは。FLYWHEELでソフトウェアエンジニアをしてますsaoiです。前回の投稿の投稿に引き続き、FLYWHEELの広告配信プラットフォームにおける、配信管理画面の認証をAuth0へと引っ越した際のお話をしようと思います。今回は実践編ということで、移行時にどのようなAuth0の機能を利用したか、また移行においてどのような点に留意したかについて書いていきます。自社実装をしていた認証フローをAuth0を用いて置き換えるにあたり、前回説明したようにAPIサーバーのデータベースのユーザーテーブルからAuth0へとユーザー情報を移し替えなければいけません。Auth0のユーザー移行ページに詳しい説明がありますがAuth0はいくつかのユーザー移行プロセスをサポートしています。Extensionを用いたJSONファイルベースによるバルク移行1の既存データベースからのマイグレーションはAuth0を使う理由となり得る強力な機能です。こちらに説明されている通り、移行中の中間状態を仮定しながら、既存ユーザー、新規サインアップユーザーの処理を自動で行います。既存データベースへの接続を行うにはEnterpriseプランの契約が必要です。魅力的な機能でしたが、移行検討時の我々のアクティブユーザー数を考慮するとEnterpriseプランはオーバーフィットだったのでこちらは採用しませんでした。今後プランのアップグレードも検討対象になるでしょう。2と3については予め作成しておいた既存ユーザーのリストを一括でインポートする形式で、特にプランなどの制約もなく使用することができますが、移行に時間がかかる場合、移行中に発生した新規ユーザーのサインアップに対応する必要があるので、予期しない中間状態を防ごうと思うと、管理画面機能の一部にダウンタイムを取る必要が出てきます(一時的に新規ユーザサインアップを停止するなどの措置)。手動の作業によるミスを極力減らすという視点からも別の方法の検討をするのが良いという考えに至りました。APIのリストと睨み合った結果、若干裏技的な次の方法を取ることにしました。APIクライアントとそのサンプルがすぐに見つかったので比較的容易に実装できそうだという見通しが立ちました。Application(SPA)とデータベースから情報を取得・更新するためのバックエンドAPIサーバーで構成されています。Auth0の設定・インテグレーションそのものについてはこちらの公式ドキュメントを参考に進めました。サンプル実装もGitHub上に豊富に公開されています。FLYWHEEL自社実装の認証においても同じくJWTを用いたトークンの振り出しと検証をしていたので、組み込みそのものは比較的スムーズに行えました。SPAとAPIサーバーでデプロイが別系統であることや、リリースのサイクル・タイミングを完全に一致させることは難しく、以下のような中間状態を想定して段階的にデプロイを行う必要がありました。新バージョンステップ0は初期状態です。トークンの発行とユーザーの管理はAPIサーバーが行っています。ステップ1ではAPIサーバーのバージョンのみを先に上げます。SPAのバージョンを先に上げてしまうとAPIサーバーがTokenの検証に失敗しAPI呼び出しが全て失敗してしまうので、先にAPIサーバーのバージョンを上げる必要があります。Userを用いたAuth0へのプロセスが走るように構成しておきます。これによって既存ユーザーの一括インポートが行われます。Userを呼んで新規ユーザーはAuth0側に作成されるように実装します。APIのLoginを発行することによって、ブラウザ経由でAuth0にアクセスしトークンを取得するのと同じ様にAuth0からアクセストークンを取得することができます。このステップによって既存・新規のユーザーは全てAuth0に作成され、ログインの際に振り出されるアクセストークンも全てAuth0が発行したものに置き換えることができます。Loginに置き換えます。Loginへ移行してしまうほうが後々の利益が大きいと判断しました。自社でログインフォームを実装・メンテナンス(例えばパスワードのポリシーチェックやフォームのセキュリティ対策など)するコストも抑えることができます。あるAuth0で置き換えることができました。これによってユーザーの認証情報を自社管理する必要がなくなり、Auth0が認証に関する各種セキュリティ対策を最新に保ってくれます(SDKのバージョン追随などは自分でする必要はあります)。当初一部のパートナー様に限って公開していた管理画面をさらに多くのパートナー様に開放するにあたって、認証に用いるメールアドレス確認とパスワードのセルフリセット機能が必要であったのですが、この2つに関してもAuth0に移行することによって機能自体の実装コストは0で追加することができました。認証プロセスにおいてこの2つは当たり前にあるべき機能なのですが、自前で実装しようと考えるとなかなかに骨が折れる作業です。管理画面用のAPIサーバーでは広告主やそこに紐づく広告などの個々のリソースに対するユーザーごとの権限情報を管理し、アクセス認可を行っています。障害対応時などに全てのオブジェクトに対して自動的に閲覧・編集権限があるような最上位の管理者権限を実装したいとなったときに、既存の権限情報を管理するテーブルを更新してそこに最上位管理者の概念を導入するとなると、なかなかの設計と実装コストがかかるという話になりました。Control)です。不正確ですが簡単に言うと「APIサービスに対して○○の操作権限を持つ」という権限情報(permission)を複数まとめてロール(role)という権限情報のセットを作り、Auth0上にあるユーザーにこのロールを割り当てる事ができます。今回は最上位管理者という新しい権限の概念をpermissionとして定義し、スーパー管理者というroleをAuth0に定義することによって、Auth0が発行するJWTに付加情報としてこの権限情報を載せました。APIサーバー側ではこの権限情報をもとに挙動を変えるという処理を実装することによって、必要な機能がDBのスキーマの変更なしに実装することができました。こちらの話についてはここで書くと長くなるので、別途詳しい内容をいつか書こうかと思います。まとめ今回は前回のPart1-導入編に引き続き、実際にどのようなプロセスとAuth0の機能を用いて認証を移行したかについて書かせて頂きました。今回紹介した移行プロセスは若干Auth0が公式に推奨しているものから外れていはいますが、移行そのものは(多少のトラブルは無論ありましたが)大変スムーズで、Auth0の開発者向けの柔軟性を実感しました。認証の移行を検討している方の参考になれば幸いです。Blogに投稿をするというのは12年+の私のエンジニア人生のなかで初めての経験で(まったくもって恥ずかしい限りですが)FLYWHEELに来なければおそらく一生機会がなかったかもしれない事でした。弊社エンジニアyukuのこの投稿にあるように、日々アウトプットを意識して仕事をして、外に発信してく作業というのは殊スタートアップでは重要なことですし、今回やってみて、エンジニア個人のキャリアとしても間違いなくプラスに働くというのが実感です。何事もやってみなければ始まらない、というのはそのとおりでした。