SmartHR Tech Blog

SmartHR 開発者ブログ

SmartHR パスキー対応の裏側 —— マルチテナントSaaSでの意思決定と実装

こんにちは。プロダクトエンジニアのutakahaです。 SmartHRでは、2025年12月9日にパスキーに対応しました。

smarthr.jp

この記事では、パスキーに対応する際の意思決定や、実装時に困ったことなどを紹介します。

パスキーを導入した背景

SmartHRでは、従業員の大事な個人情報を扱っています。そのため、不正ログインを防ぐための対策を継続的に行っています。 これまでも、2要素認証を導入し、従業員に対して2要素認証を必須とする機能を提供してきましたが、次の一手として、利便性を高めつつ、セキュリティも強化できるパスキーに対応しました。 リリースから約3ヶ月経ち、すでに5,000社を超えるテナントの従業員の皆様にご利用いただいています。

パスキーの導入は、セキュリティの向上だけでなく、企業のSmartHR管理者の運用負荷を下げる狙いもありました。 SmartHRでは、毎日、最大1,000人のユーザーがパスワードをリセットしています。 また、「パスワードが分からなくなった」という問い合わせが企業のSmartHR管理者に寄せられる状況がありました。 パスキーを提供することで、問い合わせ対応やリセット作業の負担を減らすことも目的の一つとしていました。

マルチテナントアーキテクチャにおけるRP IDの設定

ここからは、実装時にどのような判断をしたのかを紹介します。

SmartHRでは、RP IDを smarthr.jp としました。

RP ID(Relying Party Identifier)とは、WebAuthn APIにおいて、登録や認証の処理を行っているサービスのIDを表す識別子です。 サービスのドメイン名が設定され、スキームやポート番号は含まれません。

SmartHRはマルチテナントのSaaSであり、テナントはサブドメインで分かれています。 ユーザーは複数のテナントに所属できるので、RP IDにサブドメインを含めた場合、テナントごとにパスキーを登録しなければならなくなります。 テナントに縛られず、アカウントに紐づくデータとしてパスキーを扱うため、RP IDは smarthr.jp としました。

RP IDを smarthr.jp に設定するデメリットとして、WebAuthnの仕様に基づくドメイン単位でのテナント間の分離が行われなくなります。 本来であれば、ブラウザがドメイン単位で別テナントへのアクセスを遮断してくれますが、今回はアプリケーション側の実装でアクセス制御を担うことになるため、検証に細心の注意が必要になります。 SmartHRでは、アプリケーション側のログイン処理でユーザーがそのテナントに所属しているかを検証し、所属していないテナントにはログインできないようにしています。

また、もう一つのデメリットとして、SmartHRのパスキーはDiscoverable Credentialsに対応しているため、自分が所属していないテナントのログイン画面でも、ブラウザがパスキーをログイン候補として提案してしまいます。 Discoverable Credentialsとは、ユーザーがユーザー識別子(メールアドレスやユーザーIDなど)を事前に入力せずにRPにログインできる認証情報のことです。認証器の中にユーザー情報と認証情報が保存されます。 SmartHRを通常どおり利用している限り、自分が所属していないテナントのログイン画面にアクセスすることはないので、ユーザー体験としてのデメリットはないと判断しています。

パスキーのユーザー体験

SmartHRのパスキーは、パスキーをオートフィルの候補として含めるConditional UIと、「パスキーでログイン」ボタンを設置する方式の両方に対応しました。

Conditional UIとは、ユーザーがログインフォームの入力欄を選択した際、ブラウザが保存済みのパスキーを自動的に提案する仕組みです。 Conditional UIに対応することで、パスキーをフォームのオートフィルの候補に含めることが可能になります。 FIDO Allianceが提供しているPasskey Centralでは、数あるログインパターンの中でも、このオートフィルによるログインが最も高い成功率を示していることが報告されています。 パスキーの一ユーザーとしても、オートフィルはとても便利です。

ただし、SmartHRはWebサービスに慣れていないユーザーにもご利用いただいています。 そういったユーザーにとっては、ログイン画面で突然パスキーのオートフィルが表示されると混乱を生む可能性があるため、パスキーで一度ログインしたことがある(パスキーを利用する意思がある)ユーザーのみオートフィルが実行されるようにしています。 この仕様は、GitHubのパスキーを参考にしました。

Conditional UIに加えて「パスキーでログイン」ボタンも設置することで、Conditional UIが利用できないブラウザやプラットフォームのユーザーでも確実にパスキーでログインできます。 また、「パスキーでログイン」ボタンは、ユーザーにパスキーが使えることの周知にもつながります。

なお、こちらの対応は、現在のパスキーの普及度を踏まえた現時点での判断です。 今後のパスキーの成熟に合わせて、よりよいログイン体験を実現していきます。

登録できるパスキーの設計

SmartHRは会社の端末だけでなく、個人のPCやスマートフォンからもアクセスするサービスです。 ユーザーによっては、認証器を会社用とプライベート用で使い分けていることがあります。 そのため、どの端末からでもパスキーを利用できるよう、複数のパスキーを登録できるようにしました。 現実的にパスキーを数百個、数千個登録することは考えにくいため、登録できるパスキーは15個までに制限しています。

登録するパスキーの名前は、パスキー作成時のAAGUIDをもとに認証器を特定し、その名前をデフォルトの名前として登録しています。 AAGUID(Authenticator Attestation Globally Unique Identifier)とは、認証器の種別を識別する128ビットの識別子です。

同じ認証器でパスキーを複数登録する場合は、Google Password Manager 2 のように数値をインクリメントして区別しています。 この名前は初期値なので、パスキー名を変えたいユーザーが自由に編集することができます。

まとめ

この記事では、SmartHRでパスキーに対応する際の意思決定や、実装について紹介しました。 当初は狙っていなかった副次的な効果として、パスキーを利用することによって開発チームにとってもログインが便利になりました。 開発中はテストや動作確認でログインする機会が多いので、パスキーで素早くログインできるようになったことで、細かい待ち時間や入力の手間が減りました。

We Are Hiring!

SmartHRでは、認証やセキュリティの取り組みを含め、よりよいプロダクトを一緒に作る仲間を募集しています。

少しでも興味を持っていただけたら、カジュアル面談でざっくばらんにお話ししましょう!

open.talentio.com