Keycloakでクライアントを作るとき、どのグラント(認可フロー)を選ぶかで認証基盤の堅牢さは大きく変わります。Authorization Code + PKCE、Client Credentials、Device Flowという主要3グラントを、public/confidentialクライアントとリフレッシュトークンの扱いまで含めて、現場の実装判断に落とし込みます。
01まず「クライアントの種類」から決める
OIDCグラントの使い分けを語る前に、Keycloakのクライアントには2種類あることを押さえておきます。confidential(機密)クライアントはサーバサイドでシークレットを安全に保持できるアプリ、public(公開)クライアントはSPAやモバイルアプリのように、配布物のなかにシークレットを隠しきれないアプリです。Keycloakの管理コンソールでは「Client authentication」をON/OFFすることで、この区別を切り替えます(ONでconfidential、OFFでpublic)。
この区別が重要なのは、選べるグラントと必要な防御策が変わるからです。publicクライアントはclient_secretで自分を証明できないため、後述するPKCEが事実上の必須になります。逆にconfidentialクライアントであっても、PKCEを併用することは公式にも推奨されており、多層防御(defense in depth)として有効です。
02Authorization Code + PKCE — SPA/モバイルの標準解
ユーザーがログインするアプリの第一選択は、Authorization Code Flowです。ユーザーエージェントをKeycloakにリダイレクトし、認証成功後にAuthorization Codeを発行、アプリはそのコードをトークンエンドポイントでAccess Token / Refresh Token / ID Tokenに交換します。Keycloak公式も、Webアプリだけでなくモバイルを含むネイティブアプリでもこのフローを推奨しています(Securing applications and services with OpenID Connect)。
ここに必ず組み合わせるのがPKCE(Proof Key for Code Exchange, RFC 7636)です。クライアントは認可リクエスト時にランダムなcode_verifierから導出したcode_challengeを送り、トークン交換時に元のcode_verifierを提示します。これにより、たとえAuthorizationCodeが横取りされても、verifierを知らない攻撃者はトークンに交換できません。アルゴリズムは平文のplainではなくS256(SHA-256)を使うのが鉄則です。
実装面では、Keycloakの公式JavaScriptアダプタがバージョン24.0.0以降、pkceMethodをデフォルトでS256に設定するようになった点は大きな前進です(Keycloak JavaScript adapter)。アダプタ利用であれば追加設定なしでPKCEが効きますが、独自実装のフロントエンドやモバイルSDKを使う場合は、S256でchallengeを組み立てているかを必ず確認してください。
03Client Credentials — サーバ間(M2M)の認証
ユーザーが介在しない、バックエンド同士やバッチ処理の認証にはClient Credentials Grantを使います。Keycloak公式の表現を借りれば「クライアント(アプリケーションやサービス)が、ユーザーの代わりではなく自分自身としてアクセスを得たい」場合のフローです。トークンエンドポイントにclient_idとclient_secret(あるいはPrivate Key JWT)を送るだけでAccess Tokenが得られます。
このグラントは必ずconfidentialクライアントで使います。シークレットを保持できないpublicクライアントでM2Mをやろうとするのは筋が悪く、そもそも成立しません。Keycloakでは、クライアントの「Service accounts roles」を有効にすることで、そのクライアント固有のサービスアカウントにロールを割り当て、M2Mトークンの権限を最小化できます。
- ロールは絞る:サービスアカウントにrealm管理ロールを安易に付けない。呼び出し先APIが要求する最小限のクライアントロール/スコープに留めます。
- シークレット管理:client_secretはVaultやSecrets Managerで管理し、平文で構成ファイルに埋め込まない。より堅くするならクライアント認証をSecretではなくPrivate Key JWTやmTLSに切り替えます。
- audienceの制御:Client Scope/Mapperでaudience(aud)を明示し、トークンが意図しないAPIで通らないようにします(クライアントスコープとマッパーの記事も参照)。
なお、ユーザー名とパスワードを直接送るResource Owner Password Credentials(Direct Access Grants)は、M2Mの代替として使いたくなりますが、後述のとおり非推奨の流れにあります。M2MはあくまでClient Credentialsで組むのが定石です。
04Device Flow — 入力が貧弱なデバイス向け
スマートTV、CLIツール、IoT機器のように、ブラウザが無い・キーボード入力が貧弱なデバイスにはDevice Authorization Grantがあります。デバイスはKeycloakのデバイス認可エンドポイント(/realms/{realm}/protocol/openid-connect/auth/device)でdevice_codeとuser_codeを取得し、画面には「別の端末で https://... を開き、コード XXXX-YYYY を入力してください」と表示します。ユーザーは手元のスマホやPCで認証し、その間デバイスはトークンエンドポイントをポーリングして、承認され次第トークンを受け取ります。
実務上のポイントは、Device Flowはpublic・confidentialどちらのクライアントでも呼び出せることです(公式ドキュメント)。デバイス側の性質に合わせて選びます。また、ポーリング間隔(interval)とdevice_codeの有効期限を尊重した実装にしないと、Keycloak側でslow_downやexpired_tokenを返されます。ここはSDK任せにせず、レスポンスコードのハンドリングを丁寧に組んでおくと安定します。
05暗黙フロー(Implicit)はもう使わない
かつてSPAで多用されたImplicit Flowは、現在は明確に非推奨です。Keycloak公式ドキュメントも「OAuth 2.0のセキュリティに関するBest Current Practice(RFC 9700)に従い、このフローはSHOULD NOT be used(使うべきでない)」「将来のOAuth 2.1仕様からは削除される」と記しています。トークンがリダイレクトのフラグメントに直接載るためブラウザ履歴やログに漏れやすく、リフレッシュトークンも扱えません。
Keycloakでは、この流れを制度として担保するOAuth 2.1向けクライアントポリシーが用意されつつあります。GitHubのIssue #25141(Supporting OAuth 2.1)では、oauth-2-1-for-confidential-client と oauth-2-1-for-public-client という2つのプロファイルが提案・整備されており、これらはPKCEを必須化し、implicitとpasswordグラントをブロックします。confidential側はHTTPS redirect URIやmTLS等も強制します。
06リフレッシュトークンの扱いどころ
Access Tokenは短命(数分〜十数分)にして、失効の反映を早めるのが基本です。そのうえで再ログインの手間を避けるのがRefresh Tokenです。主にAuthorization Codeフロー(およびoffline_accessスコープ)で発行され、期限内であればAccess Tokenを再取得できます。一方でClient Credentials Grantでは既定では発行されず(RFC 6749 §4.4.3)、必要な場合のみクライアント設定で明示的に有効化します。M2Mでは有効期限切れのたびに新しいトークンを取得し直すのが標準的な設計です。設計上のポイントは次のとおりです。
- SSOセッションとの関係:Refresh Tokenの寿命はrealmのSSO Session Idle / Maxやクライアントのトークン設定に紐づきます。「Access Tokenは5分、Refreshは業務セッション相当」といった具合に、業務要件から逆算して決めます。
- Refresh Token Rotation:リフレッシュのたびに新しいRefresh Tokenを発行し、旧トークンを無効化する回転を有効にすると、盗まれたトークンの再利用検知に効きます。特にpublicクライアントでは検討価値が高い設定です。
- publicクライアントでの保管:SPAでRefresh Tokenをブラウザに置くこと自体のリスクを踏まえ、寿命を短めにする、Rotationを効かせる、あるいはBFF(Backend for Frontend)でトークンをサーバ側に閉じ込める設計も検討します。
- オフライントークン:ブラウザを閉じても長期間有効にしたいバッチ用途にはoffline_accessスコープによるオフライントークンがありますが、権限が長生きする分、発行対象と失効運用は厳格に管理します。
トークンの中身をどう組み立てるか、audやrolesをどう載せるかはクライアントスコープとマッパー、認証の分岐そのものの設計は認証フローの記事で掘り下げています。
07グラント選定の早見チャート
ここまでを実務の判断順に並べると、次のように整理できます。
- ユーザーがログインするWeb/SPA/モバイル → Authorization Code + PKCE。SPA/モバイルはpublic、サーバサイドWebはconfidential+PKCE。
- サーバ間・バッチ(ユーザー不在) → Client Credentials(confidential必須、サービスアカウントのロールは最小化)。
- ブラウザや入力が貧弱なデバイス → Device Flow(public/confidentialどちらも可)。
- Implicit / Resource Owner Password → 原則採用しない。既存があれば移行計画に載せる。
Quarkusベースの現行Keycloak(旧WildFly版は非推奨)では、これらのグラントとクライアントポリシーの組み合わせで、堅牢かつ運用しやすい認証基盤を組めます。バージョン差のある挙動は、稼働中のバージョンの公式ドキュメントで都度確認するのが安全です。EMWでもエンタープライズのKeycloak認証基盤を実構築しており、具体的な設計判断は導入事例もあわせてご覧ください。
—まとめ
OIDCグラントの使い分けは、「クライアントがpublicかconfidentialか」を起点に、ユーザー認証はcode+PKCE、M2MはClient Credentials、入力貧弱デバイスはDevice Flow、という3本立てに集約されます。Implicitは非推奨、PKCEはpublicで必須・confidentialでも推奨。あとはリフレッシュトークンの寿命とRotation、そしてクライアントポリシーによるガードレールで、組織全体の一貫性を担保していく——これが現場で崩れない設計指針です。