Securing Your Quarkus Application with Jakarta Persistence
Learn how to implement database-backed authentication and role-based access control in your Quarkus applications using Jakarta Persistence.
Security is no longer optional. In a world of increasing threats, compliance requirements, and user expectations, building secure applications is table stakes. And if you’re building with Quarkus you already have access to powerful tools for securing your services.
In this article, we’ll explore how to implement authentication and role-based authorization in Quarkus using Jakarta Persistence (JPA). Instead of managing users via flat configuration files, we’ll use a relational database and standard JPA annotations to manage users, passwords, and roles dynamically. This not only centralizes security but also improves maintainability, auditability, and scale.
Let’s take a look at how to build it. And take a look at the full example in my GitHub repository.
Why Back Your Security with a Database?
Centralized User Management
Managing users in code or flat files doesn’t scale. If you want to add users, change roles, or revoke access, you have to redeploy or edit sensitive files. Storing users in a database brings flexibility: you can expose an admin UI, hook into external identity providers, or script user creation.
Scalable Access Control
Modern applications have complex access requirements. Some endpoints are public, others are restricted to users or admins. Quarkus allows you to express these rules declaratively via annotations, while the database holds the truth about user roles. You get both fine-grained control and runtime flexibility.
Standardized and Secure Practices
By using Jakarta Persistence and Quarkus Security, you benefit from well-tested libraries and industry standards—like role-based access control, password hashing (e.g., Bcrypt), and extensible annotations. You’re not reinventing the wheel—you’re using robust foundations.
How to Secure a Quarkus App with Jakarta Persistence
Prerequisites
Make sure you have the following installed:
JDK 17+
Apache Maven 3.9.x
Optional: Quarkus CLI (
quarkus
)
Step 1: Scaffold the Project
Let’s generate a basic Quarkus project with the right extensions:
Using the Quarkus CLI:
quarkus create app org.acme:security-jpa-quickstart \
--extension='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
--no-code
cd security-jpa-quickstart
Or using Maven directly:
mvn io.quarkus.platform:quarkus-maven-plugin:3.21.3:create \
-DprojectGroupId=org.acme \
-DprojectArtifactId=security-jpa-quickstart \
-Dextensions='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
-DnoCode
cd security-jpa-quickstart
This sets up a minimal project with Quarkus Security JPA, Panache (a simplified ORM layer), RESTEasy Reactive, and JDBC support for PostgreSQL.
Step 2: Define the User Entity
Create a new class called User
in src/main/java/org/acme/security/jpa/User.java
:
package org.acme.security.jpa;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;
import io.quarkus.elytron.security.common.BcryptUtil;
@Entity
@Table(name = "test_user")
@UserDefinition
public class User extends PanacheEntity {
@Username
public String username;
@Password(PasswordType.CLEAR)
public String password;
@Roles
public String role;
public static void add(String username, String password, String role) {
User user = new User();
user.username = username;
// For testing I am using clear text passwords.
// YOU should use Bcrypt!
// user.password = BcryptUtil.bcryptHash(password);
user.password = password;
user.role = role;
user.persist();
}
}
What’s going on here?
@UserDefinition
: Marks this JPA entity as a security user.@Username
,@Password
,@Roles
: Map the username, password, and role fields for authentication and authorization.The
add
method simplifies adding users. 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, like we do here.
Tip: Avoid using
user
as the table name, it's a reserved keyword in many databases.
This example assumes that a user has exactly one role. Which will absolutely not be the case usually. Take a look how to externalize roles into a ManyToOne relationship.
Step 3: Configure Your Application
Open src/main/resources/application.properties
and configure your database and security:
quarkus.datasource.db-kind=postgresql
quarkus.hibernate-orm.database.generation=drop-and-create
quarkus.security.users.embedded.enabled=false
quarkus.security.basic.enabled=true
# If you are using DevServices no need to specify below
#quarkus.datasource.username=quarkus
#quarkus.datasource.password=quarkus
#quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkus_db
Key settings:
db-kind (
,username
,password
,jdbc.url)
: Configure your database.database.generation=drop-and-create
: Automatically creates tables on startup (dev only).Disables embedded users and enables HTTP Basic auth.
Step 4: Secure Your REST Endpoints
Create a simple REST endpoint with role-based access control:
package org.acme.security.jpa;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/api")
public class SecureResource {
@GET
@Path("/public")
public String publicEndpoint() {
return "This is public.";
}
@GET
@Path("/user")
@RolesAllowed("user")
public String userEndpoint() {
return "Hello, user!";
}
@GET
@Path("/admin")
@RolesAllowed("admin")
public String adminEndpoint() {
return "Hello, admin!";
}
}
Explanation:
Endpoints annotated with
@RolesAllowed
are protected.Roles must match those defined in the database
role
field.You can still have unauthenticated endpoints like
/public
.
Step 5: Add Some Test Data
Use a import.sql
file to pre-load the database:
-- src/main/resources/import.sql
INSERT INTO test_user(username, password, role) VALUES ('alice', 'alicePassword', 'admin');
INSERT INTO test_user(username, password, role) VALUES ('bob', 'bobPassword', 'user');
Quarkus will execute this automatically when started with Dev Services. Learn even more tips in this blog post from the team.
Step 6: Test The Endpoints
Then access the secure endpoints:
curl -u alice:alicePassword http://localhost:8080/api/admin
curl -u bob:bobPassword http://localhost:8080/api/user
Custom Passwords and Hashing
Security is more than just protecting access. It is also about algorithms and second factors. Spend some more time learning about how to hash passwords and best practices storing them.
Ready to Secure Your Own App?
Quarkus makes it easy to build secure, scalable, and cloud-ready applications—without the typical boilerplate or configuration pain. By using Jakarta Persistence for user and role management, you keep security logic simple, portable, and transparent.
If you’re coming from traditional Java stacks, Quarkus will feel refreshingly productive. If you’re already in the cloud-native space, it fits naturally into containerized and Kubernetes environments.
Try it for yourself:
Spin up a project at code.quarkus.io, add the security-jpa
extension, and see how fast you can go from application to secured endpoints.
Your application—and your users—deserve it.
Further Learning: Quarkus and Security
Here are some official guides and articles to dive deeper:
Quarkus Security Guide:
https://quarkus.io/guides/security
General overview of security in Quarkus, including auth, JWT, and identity providers.Security with Keycloak:
https://quarkus.io/guides/security-openid-connect
Learn how to integrate Quarkus with Keycloak or any OpenID Connect provider.JWT-Based Security:
https://quarkus.io/guides/security-jwt
Use JSON Web Tokens (JWT) for stateless authentication in REST APIs.Security JPA Guide (Source for this article):
https://quarkus.io/guides/security-jpa
The official guide to securing applications using a JPA-backed user store.Quarkus YouTube Channel:
https://www.youtube.com/@quarkusio
Watch live coding sessions and deep dives on security topics.