OpenID Connect (OIDC) の開発サービスおよび UI
このガイドでは、OpenID Connect(OIDC)のKeycloakプロバイダのDev ServicesとUIを取り上げ、他のOpenID ConnectプロバイダのDevサービスとUIをサポートする方法について説明します。また、Quarkusを開発モードで起動する前にすでに開始されているすべてのOpenID ConnectプロバイダのDev UIについても説明しています。
はじめに
Quarkus は、実験的な Dev Services For Keycloak
機能を導入しています。これは、quarkus-oidc
エクステンションが開発モードで起動され、統合テストがテストモードで実行されている場合にデフォルトで有効になります。ただし、quarkus.oidc.auth-server-url
プロパティが設定されいていない場合に限ります。開発モードかテストモード、あるいはその両方で Keycloak コンテナーを起動し、既存の Keycloak レルムを登録するか、クライアントとユーザーで新しいレルムを作成して初期化することで、Keycloak で保護された Quarkus アプリケーションの開発をすぐに開始します。application.properties
またはレルムファイルの変更が検出されると、コンテナーが再起動します。
quarkus.oidc.auth-server-url
が設定されている場合、すべての OpenID Connect プロバイダーで使用できる一般的な OpenID Connect Dev Console が有効になります。詳細は、 すべての OpenID Connect プロバイダーの Dev UI を参照してください。
Dev Services for Keycloak
次のコマンドを使用して、application.properties
の quarkus.oidc
プロパティーを設定せずにアプリケーションを起動します。
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
コンソールには以下のように表示されます。
KeyCloak Dev Services Starting:
2021-11-02 17:14:24,864 INFO [org.tes.con.wai.str.HttpWaitStrategy] (build-10) /unruffled_agnesi: Waiting for 60 seconds for URL: http://localhost:32781 (where port 32781 maps to container port 8080)
2021-11-02 17:14:44,170 INFO [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-10) Dev Services for Keycloak started.
Keycloak 管理コンソールにログインする場合、ユーザー名は |
デフォルトでは、Dev Services for Keycloak
は quarkus-dev-service-keycloak
ラベルの付いたコンテナーを見つけると新しいコンテナーを起動せず、このラベルの値が quarkus.keycloak.devservices.service-name
プロパティーの値 (デフォルト値は quarkus
) と一致する場合はこれに接続することに注意してください。その場合、以下の実行中はわずかに異なる出力が表示されます。
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
2021-08-27 18:42:43,530 INFO [io.qua.dev.com.ContainerLocator] (build-15) Dev Services container found: 48fee151a31ddfe32c39965be8f61108587b25ed2f66cdc18bb926d9e2e570c5 (quay.io/keycloak/keycloak:14.0.0). Connecting to: 0.0.0.0:32797.
2021-08-27 18:42:43,600 INFO [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-15) Dev Services for Keycloak started.
...
quarkus.keycloak.devservices.shared=false
でコンテナーの共有を無効にできることに注意してください。
次にメイン Dev UI (v1)のページを 開くと、 OpenID Connect Card
が、Keycloakのページにリンクしているのが見えます:

Provider: Keycloak
リンクをクリックすると、Keycloak ページが表示されます。このページは、Dev ServicesforKeycloak
機能がどのように設定されているかによって少し異なります。
サービスアプリケーションの開発
デフォルトでは、Quarkus OIDCサービスアプリケーション の開発をサポートするために、Keycloakページを使用することができます。
認可コード グラント
application.properties
で quarkus.oidc.devui.grant.type=code
(デフォルト値) を設定すると、authorization_code
グラントを使用してアクセストークンと ID トークンの両方が取得されます。 Single Page Application
がトークンを取得し、Quarkusサービスにアクセスする典型的なフローをエミュレートするために、このグラントを使用することが推奨されます。
まず、Log into Single Page Application
オプションが表示されます。

認証プロセスで使用されるKeycloakレルムとクライアントIDを選択します。
このSPAは、OpenId Connectのpublicクライアントを表しています。したがって、入力するクライアントIDは、シークレットのないKeycloakのpublicクライアントを指す必要があります。これは、SPAがウェブアプリケーションではないため、認可コードフローを完了するために必要なクライアントシークレットを安全に扱うことができないためです。 シークレットが必要なクライアントは、デフォルトのレルムが作成されている場合、または |
次に、 Log into Single Page Application
を選択すると、Keycloakにリダイレクトされ、例えば、 alice:alice
として認証され、SPAを表すページに戻ります:

取得したアクセストークンやIDトークンなどを確認することができます。

このビューでは、左側にエンコードされた JWT トークンが表示され、ヘッダー (赤色)、ペイロード/クレーム (緑色)、および署名 (青色) が強調表示されます。また、右側にデコードされた JWT トークンが表示され、ヘッダーとクレームの名前とその値を確認できます。
次に、相対サービスパスを入力し、トークンを送信してサービスをテストします。SPAは通常、アプリケーションのエンドポイントにアクセストークンを送信するので、例えば、 Test with Access Token
のオプションを選択します:

右下の eraser
のマークで、テスト結果エリアをクリアすることができます。
エンドポイントがSPAに現在ログインしているユーザーを認識するため、または帯域外のトークン検証を実行するために、IDトークンがベアラートークンとしてアプリケーションフロントエンドに転送されることがあります。このような場合は、 Test with ID Token
オプションを選択してください。
手動でサービスパスを入力するのは理想的ではありませんので、OIDC Dev UIですでに取得したアクセストークンを使ってサービスをテストするためのSwaggerまたはGraphQL UIの有効化については Swagger UIまたはGraphQL UIによるテスト の項をご覧ください。
最後に、ログアウトして別のユーザーとして Keycloak で認証する場合は、Log Out
image::dev-ui-keycloak-logout.png オプションを選択できます。
シングルページアプリケーションにログインしようとすると、Keycloak がエラーを返す場合があることに注意してください。たとえば、quarkus.oidc.client-id
が Keycloak にインポートされたレルムのクライアント ID と一致しない場合や、このレルムのクライアントが認可コードフローをサポートするように正しく設定されていない場合などです。このような場合、Keycloak は error_description
クエリーパラメーターと DevUI
も、このエラーの説明を表示します。以下はその例です。

エラーが発生した場合は、Keycloak Admin
オプションを使用して Keycloak にログインし、必要に応じてレルム設定を更新し、application.properties
も確認します。
Swagger UI または GraphQL UI を使用したテスト
プロジェクトで quarkus-smallrye-openapi
や quarkus-smallrye-graphql
が使用されている場合、サービスパスを手動で入力することを避け、Swagger UI
または GraphQL UI
を使用してサービスをテストできます。たとえば、quarkus-smallrye-openapi
と quarkus-smallrye-graphql
の両方の依存関係を使用して開発モードで Quarkus を起動すると、Keycloak にログインした後に次のオプションが表示されます。

例えば、 Swagger UI
をクリックすると、新しいブラウザ タブで Swagger UI
が開き、Dev UI for Keycloak が取得したトークンを使用してサービスをテストできます。 Swagger UI
は再認証を試みません。OIDC Dev UIが認証を行い、Swagger UIがテストに使用するアクセストークンを提供しているため、Swagger UIに入った後は Swagger UI
Authorize
オプションを選択しないようにしてください。
GraphQL UI
との統合も同様に機能し、Keycloak 用に Dev UI によって取得されたアクセストークンが使用されます。
Keycloak は、認証されたユーザーが設定されたリダイレクト URI にのみリダイレクトされるように強制する場合があるため、Keycloak が機能するためには Dev UI によって開始される認可コードフローのリダイレクト URI を登録する必要がある場合があります。認証要求内の正しい Keycloak がそれを強制する場合は、 この場合、右上にある コンテナーが異なるポートで実行されている複数のアプリケーション間で共有されている場合は、これらのアプリケーションごとに 特にコンテナーが複数のアプリケーション間で共有されている場合は、テスト目的でのみ カスタムレルムがインポートされていない場合、 |
インプリシット・グラント
application.properties
で quarkus.oidc.devui.grant.type=implicit
を設定すると、アクセストークンと ID トークンの両方を取得するために implicit
グラントが使用されます。認可コードグラントが機能しない場合に限り (暗示的グラントをサポートするためにクライントが Keycloak に設定されている場合など)、このグラントを使用して Single Page Application
をエミュレートします。
パスワード・グラント
application.properties
で quarkus.oidc.devui.grant.type=password
を設定すると、次のような画面が表示されます。

レルムを選択し、クライアントIDとシークレット、ユーザー名とユーザーパスワード、サービスのエンドポイントの相対パスを入力し、 Test Service
をクリックすると、 200 `, `403 `, `401
または 404
のようなステータスコードが表示されます。ユーザー名とパスワードを含む quarkus.keycloak.devservices.users
マッププロパティにユーザー名も設定されている場合は、サービスをテストする際にパスワードを設定する必要はありません。ただし、パスワードグラントを使用してサービスをテストするために、 quarkus.keycloak.devservices.users
を初期化する必要はないことに注意してください。
また、Dev UI コンソールには以下のように表示されます。
2021-07-19 17:58:11,407 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Using password grant to get a token from 'http://localhost:32818/realms/quarkus/protocol/openid-connect/token' for user 'alice' in realm 'quarkus' with client id 'quarkus-app'
2021-07-19 17:58:11,533 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Test token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6Z2tDazJQZ1JaYnVlVG5kcTFKSW1sVnNoZ2hhbWhtbnBNcXU0QUt5MnJBIn0.ey...
2021-07-19 17:58:11,536 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Sending token to 'http://localhost:8080/api/admin'
2021-07-19 17:58:11,674 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Result: 200
トークンは password
グラントを使用して Keycloak から取得され、サービスエンドポイントに送信されます。
OpenID Connect Web アプリケーションの開発
Quarkus OIDC Webアプリケーション を開発する場合、アプリケーションを起動する前に、 quarkus.oidc.application-type=web-app
を application.properties
に設定する必要があります。
次のような画面が表示されます。

相対的なサービスエンドポイントパスを設定し、Sign In To Service
をクリックすると Keycloak にリダイレクトされます。新しいブラウザータブにユーザー名とパスワードを入力し、Quarkus アプリケーションからレスポンスを取得します。
この場合、Dev UI は認可コードフローを制御してトークンを取得する Quarkus OIDC の web-app
アプリケーションであるため、開発エクスペリエンスを充実させるものではないことに注意してください。
Dev UI が OIDC web-app
アプリケーションの開発をより便利にサポートできるようにするために、quarkus.oidc.application-type
のプロファイル固有値を設定することを検討してください。
%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=service
これにより、 web-app
アプリケーションを dev モードで実行したときに、 OpenID Connectサービスアプリケーション開発 で説明したすべての Dev UI オプションが利用できるようになります。このアプローチの限界は、コードフローで返却され、Dev UIで取得されたアクセストークンとIDトークンの両方がHTTP Bearer
トークンとしてエンドポイントに送信されることです。これは、エンドポイントが IdToken
の注入を必要とする場合にはうまく機能しません。しかし、 web-app
アプリケーションが、例えば、ロールソースとして、または UserInfo
を得るためにアクセストークンを使用するだけの場合は期待通りに機能します。たとえそれが開発モードの service
アプリケーションと想定されていた場合でもです。
さらに良いオプションは、devmode で「ハイブリッド」アプリケーション タイプを使用することです:
%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=hybrid
これにより、OIDC DevUI を使用せずにブラウザーから開発モードでアプリケーションにアクセスすると、Quarkus OIDC もプロダクション モードと同様に認可コード フローを実行するようになります。 しかし、 hybrid
アプリケーションはベアラー アクセス トークンも受け入れることができるため、OIDC DevUI もより便利になります。
テストの実行
テストモードで起動した Keycloak コンテナーに対して、継続テスト モードでテストを実行できます。
また、統合テストは Dev Services for Keycloak
を使用して、Keycloak に対して実行することをお勧めします。詳しくは、 Dev Servicesを使用したOpenID connect Serviceアプリケーションのテスト と Dev Servicesを使用したOpenID Connect WebAppアプリケーションのテスト を参照してください。
Keycloak 初期化
デフォルトでは、QuarkusをベースとしたKeycloakディストリビューションを含む quay.io/keycloak/keycloak:21.0.2
イメージがコンテナの起動に使用されます。 quarkus.keycloak.devservices.image-name
で、Keycloakイメージ名を変更することが可能です。例えば、WildFlyが提供するKeycloakディストリビューションを使用するには、 quay.io/keycloak/keycloak:19.0.3-legacy
に設定します。なお、QuarkusベースのKeycloakディストリビューションは、Keycloak 20.0.0
からしか利用できません。
Dev Services for Keycloak
は、起動された Keycloak サーバーを次に初期化します。
デフォルトでは、quarkus
、secret
パスワードを持つ quarkus-app
クライアント、alice
および bob
ユーザー (名前と一致するパスワードを持つ)、 user
および admin
ロールが作成されます。このとき、alice
には admin
と user
の両方のロールが与えられ、bob
には `user`のロールが与えられます。
ユーザー名、シークレット、およびそれらのロールは、quarkus.keycloak.devservices.users
(ユーザー名とシークレットを含むマップ) および quarkus.keycloak.devservices.roles
(ユーザー名とコンマ区切りのロール値を含むマップ) でカスタマイズできます。
例えば、以下のようになります:
%dev.quarkus.keycloak.devservices.users.duke=dukePassword
%dev.quarkus.keycloak.devservices.roles.duke=reader
%dev.quarkus.keycloak.devservices.users.john=johnPassword
%dev.quarkus.keycloak.devservices.roles.john=reader,writer
この設定では、2人のユーザーを作成します。
* パスワードが dukePassword
で、ロールが reader
である duke
* パスワードが johnPassword
で、ロールが reader
および writer
である john
quarkus.oidc.client-id
と quarkus.oidc.credentials.secret
を使用して、クライアント ID とシークレットをカスタマイズできます。
ただし、Keycloak の設定はこれよりも複雑で、より多くのプロパティーを設定する必要があると思われます。
このため、デフォルトまたは設定されたレルム、クライアント、ユーザー、ロールのプロパティでKeycloakを初期化しようとする前に、 quarkus.keycloak.devservices.realm-path
が常に最初にチェックされます。realmファイルがファイルシステムまたはクラスパスに存在する場合、このrealmだけがKeycloakを初期化するために使用されます。例:
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
quarkus.keycloak.devservices.realm-path
を使って、カンマで区切られたファイルのリストを提供することで、複数のレルムファイルでKeycloakを初期化することができます:
quarkus.keycloak.devservices.realm-path=quarkus-realm1.json,quarkus-realm2.json
また、Keycloak ページには、右上隅にある KeycloakAdmin
オプションを使用して、Keycloak にサインインしてレルムを設定 (SignIn To Keycloak To Configure Realms
) するオプションがあります。

レルムのプロパティーのカスタマイズ、新規レルムの作成またはインポート、レルムのエクスポートを実行するには、Keycloak に admin:admin
としてサインインします。
Keycloak の Dev サービスを無効にする
quarkus.oidc.auth-server-url
がすでに初期化されているか、デフォルトの OIDC テナントが quarkus.oidc.tenant.enabled=false
で無効になっている場合、Keycloak を使用するかどうかにかかわらず、Dev Services ForKeycloak
はアクティブ化されません。
Dev Services for Keycloak
コンテナーを起動させない、または使用しない場合も、quarkus.keycloak.devservices.enabled=false
を使用してこの機能を無効化できます。これは、quarkus.oidc.auth-server-url
なしで quarkus:dev
を起動する予定がある場合にのみ必要です。
Dev Services for Keycloak
が無効で quarkus.oidc.auth-server-url
プロパティーが初期化されていない場合、メインの Dev UI ページには空の OpenIDConnectCard
が含まれます。

quarkus.oidc.auth-server-url
が設定されている場合、すべての OpenID Connect プロバイダーで使用できる一般的な OpenID Connect Dev Console が有効になります。詳細については、 すべての OpenID Connect プロバイダーの Dev UI を参照してください。
すべての OpenID Connect プロバイダーの Dev UI
quarkus.oidc.auth-server-url
が、すでに起動されている OpenID Connect プロバイダー (Keycloak または他のプロバイダーも可) を指し、quarkus.oidc.auth-server-url
が service
(デフォルト値) に設定され、少なくとも quarkus.oidc.client-id
が設定されている場合、すべての OpenID Connect プロバイダーの Dev UI (Dev UI for all OpenID Connect Providers
) がアクティブになります。
Keycloak や その他のプロバイダーでは、quarkus.oidc.client-id
で指定されたクライアントが使用している OpenID Connect プロバイダーの管理コンソールでパブリッククライアントとして設定されていない限り、Dev UI から開始された認可コードフローを完了するには`quarkus.oidc.credentials.secret` の設定が必要です。
実行:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
以下のメッセージが表示されます。
...
2021-09-07 15:53:42,697 INFO [io.qua.oid.dep.dev.OidcDevConsoleProcessor] (build-41) OIDC Dev Console: discovering the provider metadata at http://localhost:8180/realms/quarkus/.well-known/openid-configuration
...
プロバイダーメタデータの検出が成功した場合、メインの Dev UI ページ を開いた後、 OpenID Connect Card
のページが Dev Console
にリンクしていることがわかるでしょう:

リンクをたどると、プロバイダにログインしてトークンを取得し、アプリケーションをテストできるようになります。特にKeycloakと連携している場合は、 Dev Services for Keycloak
コンテナが開始された Keycloakの認可コードグラント のセクションで説明したような体験ができるはずです。
OpenID Connect プロバイダーが Dev Console
へ、リダイレクトで戻すことをサポートするように設定する必要がある場合がほとんどでしょう。 http://localhost:8080/q/dev-v1/io.quarkus.quarkus-oidc/provider
を、サポートされているリダイレクトおよびログアウトURLの1つにしてください。
他のプロバイダーと連携している場合、 Keycloakの認可コードグラント のセクションで説明したDev UI体験は若干異なるかもしれません。例えば、アクセストークンはJWT形式ではないため、その内部コンテンツを表示することはできませんが、すべてのプロバイダーはIDトークンをJWTとして返すはずです。
デフォルトでは、現在のアクセストークンを使用して、 |
Auth0
などの一部のプロバイダは、標準的な RP によるログアウトをサポートしていないため、ログアウトオプションを表示するには、プロバイダ固有のログアウトプロパティを構成する必要があります。詳細については、 OpenID Connect User-Initiated Logout を参照してください。
同様に、Dev UI に password
または client_credentials
グラントを使用してトークンを取得する場合は、次のような追加のプロバイダー固有プロパティーを設定する必要があります。
quarkus.oidc.devui.grant.type=password
quarkus.oidc.devui.grant-options.password.audience=http://localhost:8080
その他の OpenID Connect プロバイダーの Dev Services と UI サポート
カスタムエクステンションは、quarkus-oidc
を拡張し、プロバイダーをサポートするために必要な依存関係をエクステンションの deployment
モジュールにのみ追加する必要があります。
Dev Services
を処理するビルドステップでは、OpenID Connect Card
をプロバイダーを示す Dev UI ページにリンクするために、2 つのランタイムプロパティーを "io.quarkus.quarkus-oidc" 名前空間に追加で登録する必要があります: oidcProviderName
(例: Google
) と oidcProviderUrlBase
(例: mycompany.devservices-google
)。
package io.quarkus.oidc.okta.runtime;
import java.util.function.Supplier;
import io.quarkus.runtime.annotations.Recorder;
// This simple recorder is the only code which will be located in the extension's `runtime` module
@Recorder
public class OktaDevServicesRecorder {
public Supplier<String> getProviderName() {
return new Supplier<String>() {
@Override
public String get() {
return "OKTA";
}
};
}
public Supplier<String> getProviderUrlBase() {
return new Supplier<String>() {
@Override
public String get() {
return "io.quarkus" + "." + "quarkus-oidc-okta";
}
};
}
}
package io.quarkus.oidc.okta.deployment.devservices;
import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
import java.util.Optional;
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Consume;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.RuntimeConfigSetupCompleteBuildItem;
import io.quarkus.devconsole.spi.DevConsoleRouteBuildItem;
import io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem;
public class OktaDevConsoleProcessor {
@BuildStep(onlyIf = IsDevelopment.class)
@Record(value = RUNTIME_INIT)
public void setOidcProviderProperties(BuildProducer<DevConsoleRuntimeTemplateInfoBuildItem> provider,
OktaDevServicesRecorder recorder,
Optional<DevServicesConfigBuildItem> configProps) {
if (configProps.isPresent()) {
provider.produce(new DevConsoleRuntimeTemplateInfoBuildItem("io.quarkus", "quarkus-oidc", "oidcProviderName",
recorder.getProviderName()));
provider.produce(new DevConsoleRuntimeTemplateInfoBuildItem("io.quarkus", "quarkus-oidc", "oidcProviderUrlBase",
recorder.getProviderUrlBase()));
}
}
}
さらに、ユーザーが quarkus.keycloak.devservices.enabled=false
を入力するのではなく、エクステンションが io.quarkus.oidc.deployment.devservices.OidcProviderBuildItem
を生成してデフォルトの Dev Services for Keycloak
を無効にする必要があります。
Dev UI チュートリアルと extensions/oidc/deployment
ソースで他のアイデアも確認してください。
アプリケーション以外のルートパスに関する考慮事項
本ドキュメントでは、様々な場所でDev UI URLを以下のように表記しています: http://localhost:8080/q/dev-v1
。 q
はデフォルトの非アプリケーションルートパスです。 quarkus.http.root-path
や quarkus.http.non-application-root-path
のプロパティをカスタマイズした場合は、それに応じて q
を置き換えて下さい。詳細は Quarkusのパス解決 を参照してください。