This episode covers Quarkus security basics: HTTP authentication, role-based access control and identity stores, authentication mechanism configuration, as well as CSRF, CORS, and secure headers protection.

A public API without protection is an invitation for abuse. Security isn't an add-on feature — it's a layer that's built into the application from the start. Before discussing OAuth2 and JWT in episode 13, you need to understand the security foundations in Quarkus.
Episode 12 covers the security basics: HTTP authentication, role-based access control and identity stores, authentication mechanism configuration, as well as CSRF, CORS, and secure headers protection.
Quarkus Security has three components: an Identity Provider that authenticates users, authorization that determines access rights, and security annotations for declaring rules. Quarkus supports several mechanisms: basic, form-based, and bearer token.
The simplest way — credentials are sent in the Authorization: Basic ... header:
quarkus.http.auth.basic=trueFor development, Quarkus provides an identity store backed by property files:
quarkus.security.users.file.enabled=true
quarkus.security.users.file.plain-text=true
quarkus.security.users.file.users=users.properties
quarkus.security.users.file.roles=roles.propertiesCreate src/main/resources/users.properties containing admin=admin123 and user=user123, then roles.properties containing admin=admin,user and user=user. This is enough for development and prototyping. For production, use a database-based identity store or OIDC (episode 13).
After authentication, access control is declared with annotations:
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/api/admin")
public class AdminResource {
@GET
@RolesAllowed("admin")
public String rahasia() {
return "Hanya admin yang bisa melihat ini";
}
}@RolesAllowed("admin") restricts the endpoint to users with the admin role. Users without the role receive a 403 Forbidden.
For real applications, store users in a database. Add the extension:
./mvnw quarkus:add-extension -Dextensions=security-jdbcConfigure queries against the user tables:
quarkus.datasource.db-kind=h2
quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=\
SELECT password FROM users WHERE username = ?
quarkus.security.jdbc.principal-query.clear-password-mapper.enabled=true
quarkus.security.jdbc.principal-query.clear-password-mapper.password-index=1
quarkus.security.jdbc.principal-query.roles-query.sql=\
SELECT role FROM user_roles WHERE username = ?With security-jdbc, authentication validates the password against the users table and loads roles from the user_roles table. Always use password hashing in production — never store plain text.
Besides per-endpoint annotations, Quarkus supports path-based rules in configuration:
quarkus.http.auth.policy.only-admin.policy=role-based
quarkus.http.auth.policy.only-admin.roles=admin
quarkus.http.auth.permission.admin-route.paths=/api/admin/*
quarkus.http.auth.permission.admin-route.policy=only-adminThis configuration protects all /api/admin/* paths for the admin role only — without touching Java code.
You can read the identity of an authenticated user: inject SecurityIdentity, then identity.getPrincipal().getName() returns the username of the currently logged-in user. SecurityIdentity also exposes roles via identity.getRoles().
CORS governs which domains are allowed to call your API from a browser:
quarkus.http.cors=true
quarkus.http.cors.origins=https://app.kalian.com
quarkus.http.cors.methods=GET,POST,PUT,DELETE
quarkus.http.cors.headers=Content-Type,AuthorizationDon't set origins=* unless absolutely necessary — it opens your API to every domain.
Quarkus provides secure headers automatically through the already-installed vertx-http extension: X-Content-Type-Options, X-Frame-Options, and Strict-Transport-Security. Customize them:
quarkus.http.header."X-Content-Type-Options".value=nosniff
quarkus.http.header."Strict-Transport-Security".value=\
max-age=31536000; includeSubDomainsToken-based APIs aren't vulnerable to CSRF because tokens aren't sent automatically by the browser. For cookie-based applications, use an anti-CSRF token pattern: the server issues a random token, the client sends it in a header during data mutations, and the server validates it before processing.
Run the application with basic auth enabled:
curl -u admin:admin123 http://localhost:8080/api/admin
curl -i http://localhost:8080/api/admin
curl -u user:user123 http://localhost:8080/api/adminThe command curl -u admin:admin123 http://localhost:8080/api/admin sends basic auth credentials. Without credentials, the server returns 401; with a user lacking the admin role, it returns 403.
Episode 12 installs the first security layer of your application: understanding the Quarkus security architecture, role-based access control with annotations and HTTP permissions, authentication mechanism configuration, as well as CORS, CSRF, and secure headers protection.
Key takeaways:
@RolesAllowed("admin") restricts access based on roles.In episode 13 we'll cover OAuth2/OIDC and JWT — Quarkus OIDC integration with an external identity provider, implementing JWT authentication and authorization, service-to-service auth with token introspection, as well as token storage and refresh best practices.