2026年5月11日

Jetpack ComposeとCredential ManagerでPasskeyログインを実装してみた


Content
こんにちは!キリンです。
今回はJetpack ComposeとCredential ManagerでPasskey認証を実装してみました。

Credential Managerとは?

Credential ManagerはGoogleが提供するAndroidの認証統合APIです。
これまでID/PWログインだとログインにかかる手間が大変だったんですが、Credential Managerを使うことで鍵の生成・保存といった複雑な処理をOSレベルに委譲できるようになり(認証はサーバー側)、スマホロック解除と同じ動作でログインできるようになりました。
特にパスキーとの相性が良く、生体認証と組み合わせることでパスワード不要のログインをシンプルなコードで実現できます。

「もっと詳しく知りたい場合の公式リンク」

セットアップ方法

パスキーについて

最初に

最初はちょっと難しい印象がありましたが、実際に手を動かしてみたら、GoogleのCredential Manager APIがほとんどの処理をいい感じにやってくれて驚きました。

この記事では、Jetpack Compose + Credential Managerを使ってこのPassKeyログインを実装した流れを振り返りつつ、詰まったところや設計の考え方についてまとめていきます。同じように実装を検討している方の参考になれば嬉しいです。

実装について

実装について話す前に通常PassKeyログインの流れを記載します。

  • 通常PassKeyログインの流れ

アプリ → サーバーに「challengeをください」とリクエスト(challengeとはリプレイ攻撃を防ぐための「使い捨ての合言葉」)

サーバー → challengeを生成してレスポンス

アプリ → そのchallengeをrequestJsonに入れてgetCredential()を呼び出す

端末 → Passkeyでchallengeに署名

アプリ → 署名された結果をサーバーに送信

サーバー検証完了ログイン成功

  • UI State Management: 状態ベースの宣言的画面制御

画面の管理は、MainActivityでisLoggedInというBoolean値をひとつ持つだけにしました。ログイン成功でtrue、ログアウトでfalseに戻す、それだけです。今回のテストアプリでは、ナビゲーションライブラリなどの複雑さを排除し、単一の状態(Single Source of Truth)に依存するシンプルな設計を採用しました。

今回はパスキーの挙動確認が目的のテストアプリなので、余計な複雑さは持ち込まない判断をしました。Composeが状態変化を検知して自動的に画面を切り替えてくれるので、これで十分でした。これは Jetpack Compose の宣言的UIの特性を活かしたもので、isLoggedIn の値が変わるだけで再構成(Recomposition)が走り、画面が即座に切り替わるようになっています。

  • Passkey Registration: Credential Managerによる鍵ペア生成と保存
credentialManager.createCredential(
    context,
    CreatePublicKeyCredentialRequest(registerJson)
)

RPの情報(このパスキーがどのサービス・アプリ(RP)のためのものかを示す情報)とユーザーIDをJSONで渡すだけで、鍵ペアの生成から端末への保存まで全部やってくれます。Credential Manager API を活用することで、FIDO2/WebAuthnの複雑な仕様を意識することなく、単一のインターフェースで鍵ペアの生成、セキュアエレメントへの秘密鍵保存、生体認証UIの呼び出しをOSレベルで完結させています。

  • Passkey Authentication: 生体認証によるシームレスな認証フロー

認証時、getCredential()を呼び出すとOSがFIDO2ベースの生体認証UIを表示し、秘密鍵でchallengeに署名します。アプリは署名済みアサーションをサーバーに送信し、サーバーが公開鍵で検証することでログインが完了します。ID・パスワード不要で、秘密鍵の所有証明による安全な認証が実現します。

  • Security Trade-off: ナンス(Nonce)によるリプレイアタック対策

本来はリクエストのたびにサーバーがランダム生成して返すべきもので、リプレイアタック(再送攻撃)対策として必須の要件です。challengeナンス(Nonce)として機能し、認証のたびに変えることで盗聴された署名の再利用を防ぎます。

json
"challenge": "[ハードコーディング値]"

今回はテスト目的なので固定にしていますが、本番に持っていくなら真っ先に直さないといけない部分です。これらはあくまで意識した上での技術的割り切りです。プロダクト化の際には、動的なナンス生成とサーバー側での検証実装必要があります。

結果挙動

セキュリティ上、認証や登録する映像録画はできなかったのでスクリーンショットも追加します。

実装してみて感じたこと

今回のパスキー実装は、概念は難しそうに見えてAPIが大部分を吸収してくれるタイプで、フロント側の実装コストは正直かなり低かったです。

ただ、本番レベルにするにはサーバー側の実装が重要で、challengeの動的生成・署名検証・公開鍵の管理あたりをきちんと設計しないといけないので、そこはしっかり向き合う必要があると思っています。今回のアプリは、その手前の「動く形で理解する」ステップとして作ったものです。

実際に動かしてみて一番よかったのは、あの「IDとパスワードを入力する」という手間から完全に解放される体験ができたことです。指一本でログインが完結する瞬間、じわっと「これは便利だな」と感じました。まだ試したことがない方は、ぜひ一度その感覚を体験してみてはいかがでしょうか☺️

2026年5月11日 Jetpack ComposeとCredential ManagerでPasskeyログインを実装してみた

Category モバイル

ご意見・ご相談・料金のお見積もりなど、
お気軽にお問い合わせください。

お問い合わせはこちら