Protect a web application by using OpenID Connect (OIDC) authorization code flow

With the Quarkus OpenID Connect (OIDC) extension, you can protect application HTTP endpoints by using the OIDC Authorization Code Flow mechanism.

To learn more about the OIDC authorization code flow mechanism, see OIDC code flow mechanism for protecting web applications.

To learn about how well-known social providers such as Google, GitHub, Microsoft, Twitter, Apple, Facebook, and Spotify can be used with Quarkus OIDC, see Configuring Well-Known OpenID Connect Providers. See also, Authentication mechanisms in Quarkus.

If you want to protect your service applications by using OIDC Bearer token authentication, see OIDC Bearer token authentication.

先决条件

要完成这个指南,你需要:

  • 大概15分钟

  • 编辑器

  • 安装JDK 11以上版本并正确配置了 JAVA_HOME

  • Apache Maven 3.9.3

  • A working container runtime (Docker or Podman)

  • 如果你愿意的话,还可以选择使用Quarkus CLI

  • 如果你想构建原生可执行程序,可以选择安装Mandrel或者GraalVM,并正确配置(或者使用Docker在容器中进行构建)

应用结构

In this example, we build a very simple web application with a single page:

  • /index.html

This page is protected and can only be accessed by authenticated users.

解决方案

我们建议您按照下一节的说明逐步创建应用程序。然而,您可以直接转到已完成的示例。

克隆 Git 仓库: git clone -b 3.2 https://github.com/quarkusio/quarkus-quickstarts.git ,或下载一个 存档

The solution is located in the security-openid-connect-web-authentication-quickstart directory.

Procedure

Create the Maven project

首先,我们需要一个新的项目。使用以下命令创建一个新的项目:

CLI
quarkus create app org.acme:security-openid-connect-web-authentication-quickstart \
    --extension='resteasy-reactive,oidc' \
    --no-code
cd security-openid-connect-web-authentication-quickstart

创建Grade项目,请添加 --gradle 或者 --gradle-kotlin-dsl 参数。

For more information about how to install and use the Quarkus CLI, see the Quarkus CLI guide.

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.2.12.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-openid-connect-web-authentication-quickstart \
    -Dextensions='resteasy-reactive,oidc' \
    -DnoCode
cd security-openid-connect-web-authentication-quickstart

创建Grade项目,请添加 -DbuildTool=gradle 或者 -DbuildTool=gradle-kotlin-dsl 参数。

如果你已经配置了你的Quarkus项目,你可以通过在你的项目基础目录下运行以下命令,将 oidc 扩展加入到你的项目中去:

CLI
quarkus extension add 'oidc'
Maven
./mvnw quarkus:add-extension -Dextensions='oidc'
Gradle
./gradlew addExtension --extensions='oidc'

这将在您的构建文件中添加以下内容:

pom.xml
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-oidc</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-oidc")

Write the application

Let’s write a simple Jakarta REST resource which has all the tokens returned in the authorization code grant response injected:

package org.acme.security.openid.connect.web.authentication;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;

import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.RefreshToken;

@Path("/tokens")
public class TokenResource {

   /**
    * Injection point for the ID Token issued by the OpenID Connect Provider
    */
   @Inject
   @IdToken
   JsonWebToken idToken;

   /**
    * Injection point for the Access Token issued by the OpenID Connect Provider
    */
   @Inject
   JsonWebToken accessToken;

   /**
    * Injection point for the Refresh Token issued by the OpenID Connect Provider
    */
   @Inject
   RefreshToken refreshToken;

   /**
    * Returns the tokens available to the application. This endpoint exists only for demonstration purposes, you should not
    * expose these tokens in a real application.
    *
    * @return a HTML page containing the tokens available to the application
    */
   @GET
   @Produces("text/html")
   public String getTokens() {
       StringBuilder response = new StringBuilder().append("<html>")
               .append("<body>")
               .append("<ul>");


       Object userName = this.idToken.getClaim("preferred_username");

       if (userName != null) {
           response.append("<li>username: ").append(userName.toString()).append("</li>");
       }

       Object scopes = this.accessToken.getClaim("scope");

       if (scopes != null) {
           response.append("<li>scopes: ").append(scopes.toString()).append("</li>");
       }

       response.append("<li>refresh_token: ").append(refreshToken.getToken() != null).append("</li>");

       return response.append("</ul>").append("</body>").append("</html>").toString();
   }
}

This endpoint has ID, access, and refresh tokens injected. It returns a preferred_username claim from the ID token, a scope claim from the access token, and also a refresh token availability status.

Note that you do not have to inject the tokens - it is only required if the endpoint needs to use the ID token to interact with the currently authenticated user or use the access token to access a downstream service on behalf of this user.

Configure the application

The OIDC extension allows you to define the configuration using the application.properties file which should be located at the src/main/resources directory.

quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=frontend
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated

This is the simplest configuration you can have when enabling authentication to your application.

The quarkus.oidc.client-id property references the client_id issued by the OIDC provider and the quarkus.oidc.credentials.secret property sets the client secret.

The quarkus.oidc.application-type property is set to web-app in order to tell Quarkus that you want to enable the OIDC authorization code flow, so that your users are redirected to the OIDC provider to authenticate.

Finally, the quarkus.http.auth.permission.authenticated permission is set to tell Quarkus about the paths you want to protect. In this case, all paths are being protected by a policy that ensures that only authenticated users are allowed to access. For more information, see Security Authorization Guide.

Start and configure the Keycloak server

To start a Keycloak server, use Docker and run the following command:

docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev

其中 keycloak.version 应该设置为 17.0.0 或更高。

你应该能够通过 localhost:8180 访问你的Keycloak服务器。

To access the Keycloak Administration Console, log in as the admin user. Username should be admin and password admin.

Import the realm configuration file to create a new realm. For more information, see the Keycloak documentation about how to create a new realm.

Run the application in dev and JVM modes

要在开发模式下运行应用程序,请使用:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

When you’re done playing with dev mode, you can run it as a standard Java application.

First, compile it:

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

Then, run it:

java -jar target/quarkus-app/quarkus-run.jar

Run the application in Native mode

This same demo can be compiled into native code. No modifications are required.

这意味着您不再需要在您的生产环境中安装JVM,因为运行时技术包含在生产的二进制文件中,并以最小的资源开销优化运行。

Compilation will take a bit longer, so this step is disabled by default. You can build again by enabling the native build:

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.package.type=native

After getting a cup of coffee, you can run this binary directly:

./target/security-openid-connect-web-authentication-quickstart-runner

Test the application

To test the application, open your browser and access the following URL:

If everything is working as expected, you are redirected to the Keycloak server to authenticate.

To authenticate to the application, type the following credentials when at the Keycloak login page:

  • Username: alice

  • Password: alice

After clicking the Login button, you are redirected back to the application.

For more information about writing the integration tests that depend on Dev Services for Keycloak, see the Dev Services for Keycloak section.

Summary

Congratulations! You have learned how to set up and use the OIDC authorization code flow mechanism to protect and test application HTTP endpoints. After you have completed this tutorial, explore OIDC Bearer token authentication and other authentication mechanisms.