# 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.

## Prerequisites

To complete this guide, you need:

- Roughly 15 minutes

- An IDE

- JDK 11+ installed with `JAVA_HOME` configured appropriately

- Apache Maven 3.9.3

- A working container runtime (Docker or Podman)

- Optionally the Quarkus CLI if you want to use it

- Optionally Mandrel or GraalVM installed and configured appropriately if you want to build a native executable (or Docker if you use a native container build)

## Architecture

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.

## Solution

We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.

Clone the Git repository: `git clone https://github.com/quarkusio/quarkus-quickstarts.git`, or download an archive.

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

## Procedure

### Create the Maven project

First, we need a new project. Create a new project with the following command:

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

To create a Gradle project, add the `--gradle` or `--gradle-kotlin-dsl` option.

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.3.0:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-openid-connect-web-authentication-quickstart \
        -Dextensions='resteasy-reactive,oidc' \
        -DnoCode
    cd security-openid-connect-web-authentication-quickstart

To create a Gradle project, add the `-DbuildTool=gradle` or `-DbuildTool=gradle-kotlin-dsl` option.

For Windows users:

- If using cmd, (don’t use backward slash `\` and put everything on the same line)

- If using Powershell, wrap `-D` parameters in double quotes e.g. `"-DprojectArtifactId=security-openid-connect-web-authentication-quickstart"`

If you already have your Quarkus project configured, you can add the `oidc` extension to your project by running the following command in your project base directory:

CLI

    quarkus extension add 'oidc'

Maven

    ./mvnw quarkus:add-extension -Dextensions='oidc'

Gradle

    ./gradlew addExtension --extensions='oidc'

This will add the following to your build file:

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

where `keycloak.version` should be set to `17.0.0` or higher.

You should be able to access your Keycloak Server at localhost:8180.

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

To run the application in a dev mode, use:

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.

This implies that you no longer need to install a JVM on your production environment, as the runtime technology is included in the produced binary, and optimized to run with minimal resource overhead.

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:

- http://localhost:8080/tokens

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.

## References

- Quarkus Security overview

- OIDC code flow mechanism for protecting web applications

- Configuring well-known OpenID Connect Providers

- OpenID Connect and OAuth2 Client and Filters Reference Guide

- Dev Services for Keycloak

- Sign and encrypt JWT tokens with SmallRye JWT Build

- Choosing between OpenID Connect, SmallRye JWT, and OAuth2 authentication mechanisms

- Quarkus Keycloak Admin Client

- Keycloak Documentation

- OpenID Connect

- JSON Web Token