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)として有効です。

現場のコツ:「このアプリはシークレットを安全に保持できるか?」を最初に問う。ブラウザに配られるJSやスマホアプリのバイナリはpublic、サーバ内で完結するバックエンドはconfidential、と切り分けると、以降の判断がぶれません。

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)を使うのが鉄則です。

アプリ(public) Keycloak 1. /auth へ code_challenge(S256) を送信 2. ログイン後 Authorization Code を返却 3. /token へ code + code_verifier を提示 4. verifier検証OKなら Access/ID/Refresh Token を発行 code横取りされても verifier なしでは無効
図:Authorization Code + PKCE のトークン取得シーケンス

実装面では、Keycloakの公式JavaScriptアダプタがバージョン24.0.0以降、pkceMethodをデフォルトでS256に設定するようになった点は大きな前進です(Keycloak JavaScript adapter)。アダプタ利用であれば追加設定なしでPKCEが効きますが、独自実装のフロントエンドやモバイルSDKを使う場合は、S256でchallengeを組み立てているかを必ず確認してください。

現場のコツ:publicクライアントでは、Keycloakのクライアント設定で「Proof Key for Code Exchange Code Challenge Method」をS256に固定し、redirect URIをワイルドカードなしの完全一致に絞る。この2点だけでも、SPAの認証まわりの事故はかなり減らせます。

03Client Credentials — サーバ間(M2M)の認証

ユーザーが介在しない、バックエンド同士やバッチ処理の認証にはClient Credentials Grantを使います。Keycloak公式の表現を借りれば「クライアント(アプリケーションやサービス)が、ユーザーの代わりではなく自分自身としてアクセスを得たい」場合のフローです。トークンエンドポイントにclient_idとclient_secret(あるいはPrivate Key JWT)を送るだけでAccess Tokenが得られます。

このグラントは必ずconfidentialクライアントで使います。シークレットを保持できないpublicクライアントでM2Mをやろうとするのは筋が悪く、そもそも成立しません。Keycloakでは、クライアントの「Service accounts roles」を有効にすることで、そのクライアント固有のサービスアカウントにロールを割り当て、M2Mトークンの権限を最小化できます。

なお、ユーザー名とパスワードを直接送る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で認証し、その間デバイスはトークンエンドポイントをポーリングして、承認され次第トークンを受け取ります。

デバイス (TV / CLI / IoT) Keycloak device / token ユーザーの スマホ/PCブラウザ 1. device_code / user_code 取得 4. /token をポーリング 3. 認証 &コード入力 2. 画面のURL/コードを見て別端末で開く
図:Device Authorization Grant の全体像(デバイスとユーザー端末を分離)

実務上のポイントは、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-clientoauth-2-1-for-public-client という2つのプロファイルが提案・整備されており、これらはPKCEを必須化し、implicitとpasswordグラントをブロックします。confidential側はHTTPS redirect URIやmTLS等も強制します。

現場のコツ:新規クライアントを標準化するなら、クライアントポリシーでOAuth 2.1準拠プロファイルを既定に適用し、「implicitを有効化しようとするとポリシーで弾かれる」状態を作る。個々のクライアント設定に依存せず、組織全体でガードレールを敷けます(マルチアカウント統制の考え方と同じです)。なお、対応状況はバージョンによって差があるため、導入時は稼働中のKeycloakバージョンの公式ドキュメントで最終確認してください。

06リフレッシュトークンの扱いどころ

Access Tokenは短命(数分〜十数分)にして、失効の反映を早めるのが基本です。そのうえで再ログインの手間を避けるのがRefresh Tokenです。主にAuthorization Codeフロー(およびoffline_accessスコープ)で発行され、期限内であればAccess Tokenを再取得できます。一方でClient Credentials Grantでは既定では発行されず(RFC 6749 §4.4.3)、必要な場合のみクライアント設定で明示的に有効化します。M2Mでは有効期限切れのたびに新しいトークンを取得し直すのが標準的な設計です。設計上のポイントは次のとおりです。

トークンの中身をどう組み立てるか、audやrolesをどう載せるかはクライアントスコープとマッパー、認証の分岐そのものの設計は認証フローの記事で掘り下げています。

07グラント選定の早見チャート

ここまでを実務の判断順に並べると、次のように整理できます。

Quarkusベースの現行Keycloak(旧WildFly版は非推奨)では、これらのグラントとクライアントポリシーの組み合わせで、堅牢かつ運用しやすい認証基盤を組めます。バージョン差のある挙動は、稼働中のバージョンの公式ドキュメントで都度確認するのが安全です。EMWでもエンタープライズのKeycloak認証基盤を実構築しており、具体的な設計判断は導入事例もあわせてご覧ください。

まとめ

OIDCグラントの使い分けは、「クライアントがpublicかconfidentialか」を起点に、ユーザー認証はcode+PKCE、M2MはClient Credentials、入力貧弱デバイスはDevice Flow、という3本立てに集約されます。Implicitは非推奨、PKCEはpublicで必須・confidentialでも推奨。あとはリフレッシュトークンの寿命とRotation、そしてクライアントポリシーによるガードレールで、組織全体の一貫性を担保していく——これが現場で崩れない設計指針です。

参考(一次情報)

Keycloakでのグラント設計やクライアントポリシーの整備でお悩みでしたら、実構築の経験をふまえてお問い合わせください。

相談する
← ブログ一覧へ戻る