この記事は、NFLaboratories Advent Calendar 2024 6日目の記事*1です。
研究開発部 研究開発担当のda13daです。
今回の記事では、パスワードレスな認証を可能とするパスキーを提供する「Hanko」というサービスをご紹介します。
はじめに
従来のID/パスワード認証は、多くのサービスで採用されてきましたが、フィッシングやパスワード漏洩など、セキュリティ上の課題が指摘されています。このような背景から、セキュリティを強化しつつ、ユーザー体験を向上させるパスワードレス認証が注目を集めています。Hankoは、WebAuthnを基盤としたパスキーを活用することで、簡単かつ安全にパスワードレス認証を導入できるソリューションを提供しています。
パスキーとは
パスキーは、FIDOアライアンスが提唱する次世代認証技術で、WebAuthnを基盤にしています。この技術では、公開鍵暗号方式を利用し、ユーザーがデバイスに保存した秘密鍵を用いて認証を行います。以下は、従来のID/パスワード認証と比較した際の主な特長です。
- パスワード不要: パスワードを入力・管理する必要がないため、フィッシングやパスワード漏洩のリスクを排除します。
- 生体認証との連携: 指紋や顔認証を利用することで、直感的でスムーズなユーザー体験を提供します。
- 幅広い互換性: Windows、macOS、iOS、Androidなど主要なプラットフォームで幅広くサポートされています。
パスキーに関する仕組みは、FIDOアライアンス | How Passkeys Work*2で詳しく説明されています。
Hankoは、このパスキー技術を活用して、セキュリティと利便性を兼ね備えたパスワードレス認証を提供しています。
また、Hankoのメンバーは、パスキーの普及と教育を目的とした情報プラットフォーム*3を運営しています。
Hankoの提供形態
Hankoは、WebAuthnを基盤とした認証機能を以下の2つの方法で提供しています。
OSSプロダクト
Hankoのオープンソース版は、GitHubで公開されており、ユーザーが自身の環境に導入して利用することが可能です。高い自由度を持ち、自社システムや独自要件に応じたカスタマイズが可能です。*4
Hanko Cloud
Hanko Cloudは、IDaaS(Identity as a Service)として提供されるクラウドベースのサービスです。Hankoが用意したログイン画面や管理機能、APIを利用することで、最小限の実装作業で認証機能を組み込むことができます。
*5
今回は、Hanko Cloudを利用した方法についてご紹介します。
利用方法
1. hanko.ioのアカウント作成
まずは、hanko.ioでアカウントを作成します。
2. プロジェクト作成
プロジェクトを作成します。その際、以下の2つのprojectタイプから選択可能です。
それぞれの特徴を以下に説明します。
projectタイプについて
Hanko
- 包括的な認証とユーザー管理: パスキーを含む多様なログインオプション(ソーシャルログインや企業向けSSOなど)を提供しています。
- カスタマイズ可能なUIコンポーネント: 登録、ログイン、ユーザープロファイルのUIを簡単に組み込むことができます。
- 管理者用ダッシュボード: ユーザー管理や設定を操作可能です。
- APIベースの柔軟な統合: 全APIは有料プランでのみ利用可能です。また、有料プランで利用可能になるAPIにパスキーAPIが含まれるかについては、Hankoへの確認が必要です。
こららの特徴から、運用や管理の負担を軽減し、長期的なメンテナンスコストを抑制することが可能です。
Passkey Infrastructure
- APIベースの柔軟な統合
任意のアプリケーションにパスキー機能を組み込むためのAPIを提供しています。
このタイプは、APIベースであることから、それらに対する実装は必要なものの以下のように幅広いユースケースで活用できます。
- アカウント管理は自前で実装したい
- 既存のログイン機能を強化したい
- 特定のページでパスキーを利用したい
3. プロジェクト詳細の入力
プロジェクト名とアプリケーションURLを入力して作成します。このURLは、Hankoを統合するアプリケーションのURLを入力します。このURLは、登録後に変更可能です。
4. アプリケーションへの統合
公式サイトにフレームワークごとのHanko統合方法が示されています。*6
今回は、公式がGitHubで公開しているサンプルアプリケーション*7を使用します。
公開されているサンプルだとhankoが公開している最新バージョンに対応していなかったため、最新バージョンに対応したrepository*8を用意しました。
結合するためには、.envファイルにHANKO API URLを指定する必要があります。*9
project詳細画面にAPI URLが表示されており、これが先述した値です。
この値をコピーし、.envにその値をセットすることで、サンプルを動作させることが可能です。
上記を設定し、pnpm devで起動します。
サンプルアプリケーションでは、ログインボタンが表示されており、そのボタンを押下し遷移に従うことでアカウントを作成します。
アカウント作成時にパスキーの登録が求められます。パスキーの登録をもってアカウント登録が完了します。
アカウントの登録が完了すると、パスキーでのログインが可能となります。
パスキーによるサインインが成功すると、User idなどが表示され、成功したことがわかります。
実装について
ログイン
@teamhanko/hanko-elementsというライブラリからHankoをimportし、環境変数をセットし、hanko-authをレンダリングする以下のようなcomponentを実装し、それを呼び出すような形でHankoが用意するログインUIを利用可能です。
"use client"; import { useEffect, useCallback, useState } from "react"; import { useRouter } from "next/navigation"; import { register, Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL; export default function HankoAuth() { const router = useRouter(); const [hanko, setHanko] = useState<Hanko>(); useEffect(() => setHanko(new Hanko(hankoApi)), []); const redirectAfterLogin = useCallback(() => { // successfully logged in, redirect to a page in your application router.replace("/dashboard"); }, [router]); useEffect( () => hanko?.onSessionCreated(() => { redirectAfterLogin(); }), [hanko, redirectAfterLogin] ); useEffect(() => { register(hankoApi).catch((error) => { // handle error }); }, []); return <hanko-auth />; }
ユーザー情報の取得
こちらも同様にライブラリを用い、以下のようにhanko.user.getCurrent()を実行することで、現在ログインしているユーザーの情報が取得可能です。
"use client"; import { useState, useEffect } from "react"; import { Hanko } from "@teamhanko/hanko-elements"; const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || ""; interface HankoUser { id: string; email: string; loading: boolean; error: string | null; } export function useUserData(): HankoUser { const [hanko, setHanko] = useState<Hanko>(); const [userState, setUserState] = useState<HankoUser>({ id: "", email: "", loading: true, error: null, }); useEffect(() => setHanko(new Hanko(hankoApi)), []); useEffect(() => { hanko?.user .getCurrent() .then(({ id, email }) => { setUserState({ id, email, loading: false, error: null }); }) .catch((error) => { setUserState((prevState) => ({ ...prevState, loading: false, error })); }); }, [hanko]); return userState; }
パスキーAPIについて
projectタイプ「Passkey Infrastructure」を選択した場合、Standalone Passkey APIが利用可能です。*10
パスキーAPIを利用した場合に必要な実装についても簡単に紹介します。
主なAPIエンドポイント
パスキーのみでログインを実装する場合は、以下の4つのAPIを利用します。
これらのAPIをバックエンドから呼び出すことでパスキーの登録およびログインが可能となります。
4つのAPIを利用する際に参考になりそうなサンプル実装として、passkeys-python*15がHankoTeamによって公開されています。
ID/パスワード認証 + パスキー認証を併用する場合は、以下のAPIを利用します。
注意点として、組織によってMFAのon/offを切り替えるようなケースにおいては、前者(パスキーのみのAPI)とMFA用(ID/パスワード認証 + パスキー認証)のAPIの両方を使用した実装が必要です。
こちらに関してサンプル実装は存在しませんが、上記と同様の方法で実装可能です。
終わりに
Hankoを導入することで、セキュリティとユーザー体験を向上させるためのパスキーを簡単に提供することが可能です。また、今回ご紹介していない項目として、ユーザーのパスワードに関するルールや2FAなど認証に関する細かい設定も可能となっています。
この記事を参考に、Hankoを活用したパスキーの導入を検討してみてください。
*1:https://adventar.org/calendars/10492
*2:https://www.passkeycentral.org/introduction-to-passkeys/how-passkeys-work
*4:https://github.com/teamhanko/hanko
*6:Integrate Hanko with Next.js - Hanko
*7:https://github.com/teamhanko/hanko-nextjs-starter
*8:https://github.com/da13da/hanko-nextjs-starter
*9:https://github.com/da13da/hanko-nextjs-starter/blob/main/.env.example#L1
*10:https://docs.hanko.io/passkey-api/introduction
*11:https://docs.hanko.io/passkey-api/reference/credentials/start-passkey-registration
*12:https://docs.hanko.io/passkey-api/reference/credentials/finish-passkey-registration
*13:https://docs.hanko.io/passkey-api/reference/start-login
*14:https://docs.hanko.io/passkey-api/reference/finish-login
*15:https://github.com/teamhanko/passkeys-python/blob/main/python-backend/app.py
*16:https://docs.hanko.io/passkey-api/reference/credentials/start-mfa-registration
*17:https://docs.hanko.io/passkey-api/reference/credentials/finish-mfa-registration
*18:https://docs.hanko.io/passkey-api/reference/credentials/start-mfa-login
*19:https://docs.hanko.io/passkey-api/reference/credentials/finish-mfa-login