Red Hat build of Quarkus 3.8
Getting started with security
Last Updated: 2024-07-24
Red Hat build of Quarkus 3.8 Getting started with security
Legal Notice
Copyright © 2024 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons
Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is
available at
http://creativecommons.org/licenses/by-sa/3.0/
. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must
provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert,
Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift,
Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States
and other countries.
Linux ® is the registered trademark of Linus Torvalds in the United States and other countries.
Java ® is a registered trademark of Oracle and/or its affiliates.
XFS ® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States
and/or other countries.
MySQL ® is a registered trademark of MySQL AB in the United States, the European Union and
other countries.
Node.js ® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the
official Joyent Node.js open source or commercial project.
The OpenStack ® Word Mark and OpenStack logo are either registered trademarks/service marks
or trademarks/service marks of the OpenStack Foundation, in the United States and other
countries and are used with the OpenStack Foundation's permission. We are not affiliated with,
endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Abstract
This guide demonstrates how to secure Quarkus applications by using Basic authentication and
Jakarta Persistence, guiding you through prerequisites, application setup, and testing. It covers
creating a Maven project, verifying dependencies, writing application endpoints, defining user
entities, and configuring Basic authentication. It includes testing the application with Dev Services
for PostgreSQL, compiling, running, and verifying application security using curl or a browser. By
the end, you’ll understand how to implement role-based access control, readying you for more
advanced mechanisms like OIDC. It details using Jakarta Persistence for security, including entity
specifications, role storage, and password hashing.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Table of Contents
PROVIDING FEEDBACK ON RED HAT BUILD OF QUARKUS DOCUMENTATION
MAKING OPEN SOURCE MORE INCLUSIVE
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA
PERSISTENCE
1.1. PREREQUISITES
1.2. BUILDING YOUR APPLICATION
1.3. CREATE AND VERIFY THE MAVEN PROJECT
1.3.1. Create the Maven project
1.3.2. Verify the quarkus-security-jpa dependency
1.4. WRITE THE APPLICATION
1.5. DEFINE THE USER ENTITY
1.6. CONFIGURE THE APPLICATION
1.7. TEST YOUR APPLICATION BY USING DEV SERVICES FOR POSTGRESQL
1.7.1. Use curl or a browser to test your application
1.7.2. Compile and run the application
1.7.3. Access and test the application security
1.7.4. Results
1.8. WHAT’S NEXT
1.9. REFERENCES
CHAPTER 2. QUARKUS SECURITY WITH JAKARTA PERSISTENCE
2.1. JAKARTA PERSISTENCE ENTITY SPECIFICATION
2.2. JAKARTA PERSISTENCE ENTITY AS STORAGE OF ROLES
2.3. PASSWORD STORAGE AND HASHING
2.4. REFERENCES
3
4
5
5
5
6
6
7
7
9
10
11
13
13
14
15
15
16
17
17
18
19
21
Table of Contents
1
Red Hat build of Quarkus 3.8 Getting started with security
2
PROVIDING FEEDBACK ON RED HAT BUILD OF QUARKUS
DOCUMENTATION
To report an error or to improve our documentation, log in to your Red Hat Jira account and submit an
issue. If you do not have a Red Hat Jira account, then you will be prompted to create an account.
Procedure
1. Click the following link to create a ticket.
2. Enter a brief description of the issue in the Summary.
3. Provide a detailed description of the issue or enhancement in the Description. Include a URL to
where the issue occurs in the documentation.
4. Clicking Submit creates and routes the issue to the appropriate documentation team.
PROVIDING FEEDBACK ON RED HAT BUILD OF QUARKUS DOCUMENTATION
3
MAKING OPEN SOURCE MORE INCLUSIVE
Red Hat is committed to replacing problematic language in our code, documentation, and web
properties. We are beginning with these four terms: master, slave, blacklist, and whitelist. Because of the
enormity of this endeavor, these changes will be implemented gradually over several upcoming releases.
For more details, see our CTO Chris Wright’s message .
Red Hat build of Quarkus 3.8 Getting started with security
4
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING
BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
Get started with Quarkus Security by securing your Quarkus application endpoints with the built-in
Quarkus Basic authentication and the Jakarta Persistence identity provider, enabling role-based access
control.
The Jakarta Persistence IdentityProvider verifies and converts a Basic authentication user name and
password pair to a SecurityIdentity instance, which is used to authorize access requests, making your
Quarkus application secure.
For more information about Jakarta Persistence, see the Quarkus Security with Jakarta Persistence
guide.
This tutorial prepares you to implement more advanced security mechanisms in Quarkus, for example,
how to use the OpenID Connect (OIDC) authentication mechanism.
1.1. PREREQUISITES
To complete this guide, you need:
Roughly 15 minutes
An IDE
JDK 17+ installed with JAVA_HOME configured appropriately
Apache Maven 3.9.6
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)
1.2. BUILDING YOUR APPLICATION
This tutorial gives detailed steps for creating an application with endpoints that illustrate various
authorization policies:
Endpoint Description
/api/public Accessible without authentication, this endpoint allows anonymous
access.
/api/admin Secured with role-based access control (RBAC), this endpoint is
accessible only to users with the admin role. Access is controlled
declaratively by using the @RolesAllowed annotation.
/api/users/me Also secured by RBAC, this endpoint is accessible only to users with the
user role. It returns the caller’s username as a string.
TIP
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
5
TIP
To examine the completed example, download the archive or clone the Git repository:
You can find the solution in the security-jpa-quickstart directory.
1.3. CREATE AND VERIFY THE MAVEN PROJECT
For Quarkus Security to be able to map your security source to Jakarta Persistence entities, ensure that
the Maven project in this tutorial includes the quarkus-security-jpa extension.
NOTE
Hibernate ORM with Panache is used to store your user identities, but you can also use
Hibernate ORM with the quarkus-security-jpa extension.
You must also add your preferred database connector library. The instructions in this
example tutorial use a PostgreSQL database for the identity store.
1.3.1. Create the Maven project
You can create a new Maven project with the Security Jakarta Persistence extension or add the
extension to an existing Maven project. You can use either Hibernate ORM or Hibernate Reactive.
To create a new Maven project with the Jakarta Persistence extension, complete one of the
following steps:
To create the Maven project with Hibernate ORM, use the following command:
Using the Quarkus CLI:
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.
Using Maven:
To create a Gradle project, add the -DbuildTool=gradle or -DbuildTool=gradle-kotlin-dsl
option.
For Windows users:
git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.8
quarkus create app org.acme:security-jpa-quickstart \
--extension='security-jpa,jdbc-postgresql,resteasy-reactive,hibernate-orm-panache' \
--no-code
cd security-jpa-quickstart
mvn io.quarkus.platform:quarkus-maven-plugin:3.8.5:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=security-jpa-quickstart \
-Dextensions='security-jpa,jdbc-postgresql,resteasy-reactive,hibernate-orm-panache' \
-DnoCode
cd security-jpa-quickstart
Red Hat build of Quarkus 3.8 Getting started with security
6
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-
jpa-quickstart"
To add the Jakarta Persistence extension to an existing Maven project, complete one of the
following steps:
To add the Security Jakarta Persistence extension to an existing Maven project with
Hibernate ORM, run the following command from your project base directory:
Using the Quarkus CLI:
Using Maven:
Using Gradle:
1.3.2. Verify the quarkus-security-jpa dependency
After you have run either of the preceding commands to create the Maven project, verify that the
quarkus-security-jpa dependency was added to your project build XML file.
To verify the quarkus-security-jpa extension, check for the following configuration:
Using Maven:
Using Gradle:
1.4. WRITE THE APPLICATION
Secure the API endpoint to determine who can access the application by using one of the
following approaches:
Implement the /api/public endpoint to allow all users access to the application. Add a
regular Jakarta REST resource to your Java source code, as shown in the following code
snippet:
quarkus extension add security-jpa
./mvnw quarkus:add-extension -Dextensions='security-jpa'
./gradlew addExtension --extensions='security-jpa'
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa</artifactId>
</dependency>
implementation("io.quarkus:quarkus-security-jpa")
package org.acme.security.jpa;
import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
7
Implement an /api/admin endpoint that can only be accessed by users who have the admin
role. The source code for the /api/admin endpoint is similar, but instead, you use a
@RolesAllowed annotation to ensure that only users granted the admin role can access
the endpoint. Add a Jakarta REST resource with the following @RolesAllowed annotation:
Implement an /api/users/me endpoint that can only be accessed by users who have the
user role. Use SecurityContext to get access to the currently authenticated Principal user
and to return their username, all of which is retrieved from the database.
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api/public")
public class PublicResource {
@GET
@PermitAll
@Produces(MediaType.TEXT_PLAIN)
public String publicResource() {
return "public";
}
}
package org.acme.security.jpa;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/api/admin")
public class AdminResource {
@GET
@RolesAllowed("admin")
@Produces(MediaType.TEXT_PLAIN)
public String adminResource() {
return "admin";
}
}
package org.acme.security.jpa;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
@Path("/api/users")
public class UserResource {
Red Hat build of Quarkus 3.8 Getting started with security
8
1.5. DEFINE THE USER ENTITY
You can now describe how you want security information to be stored in the model by adding
annotations to the user entity, as outlined in the following code snippet:
The quarkus-security-jpa extension only initializes if a single entity is annotated with @UserDefinition.
The @UserDefinition annotation must be present on a single entity, either a regular Hibernate
@GET
@RolesAllowed("user")
@Path("/me")
public String me(@Context SecurityContext securityContext) {
return securityContext.getUserPrincipal().getName();
}
}
package org.acme.security.jpa;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.elytron.security.common.BcryptUtil;
import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;
@Entity
@Table(name = "test_user")
@UserDefinition 1
public class User extends PanacheEntity {
@Username 2
public String username;
@Password 3
public String password;
@Roles 4
public String role;
/**
* Adds a new user to the database
* @param username the username
* @param password the unencrypted password (it is encrypted with bcrypt)
* @param role the comma-separated roles
*/
public static void add(String username, String password, String role) { 5
User user = new User();
user.username = username;
user.password = BcryptUtil.bcryptHash(password);
user.role = role;
user.persist();
}
}
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
9
1
2
3
4
5
The @UserDefinition annotation must be present on a single entity, either a regular Hibernate
ORM entity or a Hibernate ORM with Panache entity.
Indicates the field used for the username.
Indicates the field used for the password. By default, it uses bcrypt-hashed passwords. You can
configure it to use plain text or custom passwords.
Indicates the comma-separated list of roles added to the target principal representation attributes.
Allows us to add users while hashing passwords with the proper bcrypt hash.
NOTE
Don’t forget to set up the Panache and PostgreSQL JDBC driver, please see Setting up
and configuring Hibernate ORM with Panache for more information.
1.6. CONFIGURE THE APPLICATION
1. Enable the built-in Quarkus Basic authentication mechanism by setting the
quarkus.http.auth.basic property to true:
quarkus.http.auth.basic=true
NOTE
When secure access is required, and no other authentication mechanisms are
enabled, the built-in Basic authentication of Quarkus is the fallback
authentication mechanism. Therefore, in this tutorial, you do not need to set the
property quarkus.http.auth.basic to true.
2. Configure at least one data source in the application.properties file so the quarkus-security-
jpa extension can access your database. For example:
3. To initialize the database with users and roles, implement the Startup class, as outlined in the
following code snippet:
quarkus.http.auth.basic=true
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.url=jdbc:postgresql:security_jpa
quarkus.hibernate-orm.database.generation=drop-and-create
package org.acme.security.jpa;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Singleton;
import jakarta.transaction.Transactional;
import io.quarkus.runtime.StartupEvent;
Red Hat build of Quarkus 3.8 Getting started with security
10
The preceding example demonstrates how the application can be protected and identities provided by
the specified database.
IMPORTANT
In a production environment, do not store plain text passwords. As a result, the quarkus-
security-jpa defaults to using bcrypt-hashed passwords.
1.7. TEST YOUR APPLICATION BY USING DEV SERVICES FOR
POSTGRESQL
Complete the integration testing of your application in JVM and native modes by using Dev Services for
PostgreSQL before you run your application in production mode.
Start by adding the following dependencies to your test project:
Using Maven:
Using Gradle:
To run your application in dev mode:
Using the Quarkus CLI:
Using Maven:
Using Gradle:
@Singleton
public class Startup {
@Transactional
public void loadUsers(@Observes StartupEvent evt) {
// reset and load all test users
User.deleteAll();
User.add("admin", "admin", "admin");
User.add("user", "user", "user");
}
}
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.rest-assured:rest-assured")
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
11
The following properties configuration demonstrates how to enable PostgreSQL testing to run
only in production (prod) mode. In this scenario, Dev Services for PostgreSQL launches and
configures a PostgreSQL test container.
If you add the %prod. profile prefix, data source properties are not visible to Dev Services for
PostgreSQL and are only observed by an application running in production mode.
To write the integration test, use the following code sample:
%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.username=quarkus
%prod.quarkus.datasource.password=quarkus
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql:elytron_security_jpa
quarkus.hibernate-orm.database.generation=drop-and-create
package org.acme.security.jpa;
import static io.restassured.RestAssured.get;
import static io.restassured.RestAssured.given;
import static org.hamcrest.core.Is.is;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
public class JpaSecurityRealmTest {
@Test
void shouldAccessPublicWhenAnonymous() {
get("/api/public")
.then()
.statusCode(HttpStatus.SC_OK);
}
@Test
void shouldNotAccessAdminWhenAnonymous() {
get("/api/admin")
.then()
.statusCode(HttpStatus.SC_UNAUTHORIZED);
}
@Test
void shouldAccessAdminWhenAdminAuthenticated() {
given()
.auth().preemptive().basic("admin", "admin")
.when()
.get("/api/admin")
.then()
.statusCode(HttpStatus.SC_OK);
Red Hat build of Quarkus 3.8 Getting started with security
12
As you can see in this code sample, you do not need to start the test container from the test code.
NOTE
When you start your application in dev mode, Dev Services for PostgreSQL launches a
PostgreSQL dev mode container so that you can start developing your application. While
developing your application, you can add and run tests individually by using the
Continuous Testing feature. Dev Services for PostgreSQL supports testing while you
develop by providing a separate PostgreSQL test container that does not conflict with
the dev mode container.
1.7.1. Use curl or a browser to test your application
Use the following example to start the PostgreSQL server:
docker run --rm=true --name security-getting-started -e POSTGRES_USER=quarkus \
-e POSTGRES_PASSWORD=quarkus -e POSTGRES_DB=elytron_security_jpa \
-p 5432:5432 postgres:14.1
1.7.2. Compile and run the application
Compile and run your Quarkus application by using one of the following methods:
JVM mode
1. Compile the application:
Using the Quarkus CLI:
}
@Test
void shouldNotAccessUserWhenAdminAuthenticated() {
given()
.auth().preemptive().basic("admin", "admin")
.when()
.get("/api/users/me")
.then()
.statusCode(HttpStatus.SC_FORBIDDEN);
}
@Test
void shouldAccessUserAndGetIdentityWhenUserAuthenticated() {
given()
.auth().preemptive().basic("user", "user")
.when()
.get("/api/users/me")
.then()
.statusCode(HttpStatus.SC_OK)
.body(is("user"));
}
}
quarkus build
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
13
Using Maven:
Using Gradle:
2. Run the application:
Native mode
1. Compile the application:
Using the Quarkus CLI:
Using Maven:
Using Gradle:
2. Run the application:
1.7.3. Access and test the application security
When your application is running, you can access its endpoints by using one of the following Curl
commands.
Connect to a protected endpoint anonymously:
Connect to a protected endpoint anonymously:
./mvnw install
./gradlew build
java -jar target/quarkus-app/quarkus-run.jar
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.package.type=native
./target/security-jpa-quickstart-1.0.0-SNAPSHOT-runner
$ curl -i -X GET http://localhost:8080/api/public
HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain;charset=UTF-8
public
$ curl -i -X GET http://localhost:8080/api/admin
HTTP/1.1 401 Unauthorized
Content-Length: 14
Red Hat build of Quarkus 3.8 Getting started with security
14
Connect to a protected endpoint as an authorized user:
You can also access the same endpoint URLs by using a browser.
NOTE
If you use a browser to connect to a protected resource anonymously, a Basic
authentication form displays, prompting you to enter credentials.
1.7.4. Results
When you provide the credentials of an authorized user, for example, admin:admin, the Jakarta
Persistence security extension authenticates and loads the user’s roles. The admin user is authorized to
access the protected resources.
If a resource is protected with @RolesAllowed("user"), the user admin is not authorized to access the
resource because it is not assigned to the "user" role, as shown in the following example:
Finally, the user named user is authorized, and the security context contains the principal details, for
example, the username.
1.8. WHAT’S NEXT
You have successfully learned how to create and test a secure Quarkus application. This was achieved
Content-Type: text/html;charset=UTF-8
WWW-Authenticate: Basic
Not authorized
$ curl -i -X GET -u admin:admin http://localhost:8080/api/admin
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain;charset=UTF-8
admin
$ curl -i -X GET -u admin:admin http://localhost:8080/api/users/me
HTTP/1.1 403 Forbidden
Content-Length: 34
Content-Type: text/html;charset=UTF-8
Forbidden
$ curl -i -X GET -u user:user http://localhost:8080/api/users/me
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain;charset=UTF-8
user
CHAPTER 1. GETTING STARTED WITH SECURITY BY USING BASIC AUTHENTICATION AND JAKARTA PERSISTENCE
15
You have successfully learned how to create and test a secure Quarkus application. This was achieved
by integrating the built-in Basic authentication in Quarkus with the Jakarta Persistence identity
provider.
After completing this tutorial, you can explore more advanced security mechanisms in Quarkus. The
following information shows you how to use OpenID Connect for secure single sign-on access to your
Quarkus endpoints:
OIDC Bearer token authentication
OIDC code flow mechanism for protecting web applications
1.9. REFERENCES
Quarkus Security overview
Quarkus Security architecture
Other supported authentication mechanisms
Identity providers
OIDC Bearer token authentication
OIDC code flow mechanism for protecting web applications
Simplified Hibernate ORM with Panache
Using Hibernate ORM and Jakarta Persistence
Red Hat build of Quarkus 3.8 Getting started with security
16
CHAPTER 2. QUARKUS SECURITY WITH JAKARTA
PERSISTENCE
You can configure your application to use Jakarta Persistence to store users' identities.
Quarkus provides a Jakarta Persistence identity provider, similar to the JDBC identity provider. Jakarta
Persistence is suitable for use with the Basic and Form-based Quarkus Security mechanisms, which
require username and password credentials.
The Jakarta Persistence IdentityProvider creates a SecurityIdentity instance. During user
authentication, this instance is used to verify and authorize access requests.
For a practical example, see the Getting started with Security using Basic authentication and Jakarta
Persistence tutorial.
2.1. JAKARTA PERSISTENCE ENTITY SPECIFICATION
Quarkus security offers a Jakarta Persistence integration to collect usernames, passwords, and roles and
store them into Jakarta Persistence database entities.
The following Jakarta Persistence entity specification demonstrates how users' information needs to be
stored in a Jakarta Persistence entity and correctly mapped so that Quarkus can retrieve this
information from a database.
The @UserDefinition annotation must be present on a Jakarta Persistence entity, regardless of
whether simplified Hibernate ORM with Panache is used or not.
The @Username and @Password field types are always String.
The @Roles field must either be String, Collection<String>, or a Collection<X>, where X is an
entity class with a single String field annotated as @RolesValue.
Each String role element type is parsed as a comma-separated list of roles.
The following example demonstrates storing security information by adding annotations to the user
entity:
package org.acme.security.jpa;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.elytron.security.common.BcryptUtil;
import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;
@Entity
@Table(name = "test_user")
@UserDefinition 1
public class User extends PanacheEntity {
@Username 2
public String username;
CHAPTER 2. QUARKUS SECURITY WITH JAKARTA PERSISTENCE
17
1
2
3
4
5
The quarkus-security-jpa extension initializes only if a single entity is annotated with @UserDefinition.
The @UserDefinition annotation must be present on a single entity, either a regular Hibernate
ORM entity or a Hibernate ORM with Panache entity.
Indicates the field used for the username.
Indicates the field used for the password. By default, quarkus-security-jpa uses bcrypt-hashed
passwords, or you can configure plain text or custom passwords instead.
This indicates the comma-separated list of roles added to the target principal representation
attributes.
This method lets you add users while hashing passwords with the proper bcrypt hash.
2.2. JAKARTA PERSISTENCE ENTITY AS STORAGE OF ROLES
Use the following example to store roles inside another Jakarta Persistence entity:
@Password 3
public String password;
@Roles 4
public String role;
/**
* Adds a new user to the database
* @param username the username
* @param password the unencrypted password (it is encrypted with bcrypt)
* @param role the comma-separated roles
*/
public static void add(String username, String password, String role) { 5
User user = new User();
user.username = username;
user.password = BcryptUtil.bcryptHash(password);
user.role = role;
user.persist();
}
}
@UserDefinition
@Table(name = "test_user")
@Entity
public class User extends PanacheEntity {
@Username
public String name;
@Password
public String pass;
@ManyToMany
@Roles
public List<Role> roles = new ArrayList<>();
}
Red Hat build of Quarkus 3.8 Getting started with security
18
NOTE
This example demonstrates storing and accessing roles. To update an existing user or
create a new one, annotate public List<Role> roles with
@Cascade(CascadeType.ALL) or choose a specific CascadeType.
2.3. PASSWORD STORAGE AND HASHING
When developing applications with Quarkus, you can decide how to manage password storage and
hashing. You can keep the default password and hashing settings of Quarkus, or you can hash passwords
manually.
With the default option, passwords are stored and hashed with bcrypt under the Modular Crypt Format
(MCF). While using MCF, the hashing algorithm, iteration count, and salt are stored as a part of the
hashed value. As such, we do not need dedicated columns to keep them.
NOTE
In cryptography, a salt is a name for random data used as an additional input to a one-way
function that hashes data, a password, or a passphrase.
To represent passwords stored in the database that were hashed by different algorithms, create a class
that implements org.wildfly.security.password.PasswordProvider as shown in the following example.
The following snippet shows how to set a custom password provider that represents a password that
was hashed with the SHA256 hashing algorithm.
@Entity
public class Role extends PanacheEntity {
@ManyToMany(mappedBy = "roles")
public List<User> users;
@RolesValue
public String role;
}
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.PasswordType;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;
@UserDefinition
@Table(name = "test_user")
@Entity
public class CustomPasswordUserEntity {
@Id
CHAPTER 2. QUARKUS SECURITY WITH JAKARTA PERSISTENCE
19
TIP
To quickly create a hashed password, use String BcryptUtil.bcryptHash(String password), which
defaults to creating a random salt and hashing in ten iterations. This method also allows specifying the
number of iterations and salt used.
WARNING
For applications running in a production environment, do not store passwords as
plain text.
However, it is possible to store passwords as plain text with the
@Password(PasswordType.CLEAR) annotation when operating in a test
environment.
TIP
@GeneratedValue
public Long id;
@Column(name = "username")
@Username
public String name;
@Column(name = "password")
@Password(value = PasswordType.CUSTOM, provider = CustomPasswordProvider.class)
public String pass;
@Roles
public String role;
}
import jakarta.xml.bind.DatatypeConverter;
import org.wildfly.security.password.Password;
import org.wildfly.security.password.interfaces.SimpleDigestPassword;
import io.quarkus.security.jpa.PasswordProvider;
public class CustomPasswordProvider implements PasswordProvider {
@Override
public Password getPassword(String passwordInDatabase) {
byte[] digest = DatatypeConverter.parseHexBinary(passwordInDatabase);
// Let the security runtime know that this passwordInDatabase is hashed by using the SHA256
hashing algorithm
return
SimpleDigestPassword.createRaw(SimpleDigestPassword.ALGORITHM_SIMPLE_DIGEST_SHA_256,
digest);
}
}
Red Hat build of Quarkus 3.8 Getting started with security
20
TIP
The Hibernate Multitenancy is supported, and you can store the user entity in a persistence unit with
enabled multitenancy. However, if your io.quarkus.hibernate.orm.runtime.tenant.TenantResolver
must access the io.vertx.ext.web.RoutingContext to resolve request details, you must disable
proactive authentication. For more information about proactive authentication, see the Quarkus
Proactive authentication guide.
Configuration property fixed at build time - All other configuration properties are overridable at
runtime
Configuration property Type Defaul
t
quarkus.security-jpa.persistence-unit-name
Selects the Hibernate ORM persistence unit. Default persistence unit is used when no
value is specified.
Environment variable:
QUARKUS_SECURITY_JPA_PERSISTENCE_UNIT_NAME
string <defa
ult>
2.4. REFERENCES
Getting started with Security by using Basic authentication and Jakarta Persistence
Identity providers
Quarkus Security overview
CHAPTER 2. QUARKUS SECURITY WITH JAKARTA PERSISTENCE
21