La nuit tombe sur la taverne. Les tables se vident, les bougies vacillent, et il ne reste plus qu'un dernier problème a régler : protéger le cellier.
Les roublards, voleurs et nains trop voraces rôdent. S'ils mettent la main sur les provisions et la bière, l'auberge est perdue.
Dans cet article, on met en place Basic Auth dans Quarkus avec trois approches, dans cet ordre :
- utilisateurs embarques
- utilisateurs stockes en base via JDBC
- utilisateurs stockes via JPA
Resume rapide
| Approche | Ou sont les utilisateurs | Quand l'utiliser |
|---|---|---|
| Embedded | Dans application.properties |
Demo, POC, cas ultra simples |
| JDBC | En base, via requete SQL | Besoin d'un stockage simple et direct |
| JPA | En base, via entite JPA | Modele evolutif et besoin de domain modeling |
Encart pour les habitués de Spring Boot
Si tu viens de Spring Boot, certains reflexes vont te manquer ici, et c'est normal :
- Pas de
UserDetailsServicea implementer : Quarkus branche un Identity Provider directement depuis les dépendances declarées. - Pas de classe de configuration securite : la plupart des règles passent par
application.propertieset les annotations (@RolesAllowed).
Dans nos trois exemples, c'est Quarkus qui fournit l'identité en fonction du module :
- utilisateurs embarques avec
quarkus-elytron-security-properties-file - utilisateurs en base via
quarkus-elytron-security-jdbc - utilisateurs via JPA avec
quarkus-security-jpa
Tu te concentres sur les endpoints et les roles, le reste est geré par le moteur de sécurité.
Basic Auth, en pratique
Basic Auth est un mécanisme tres simple :
- Le client envoie un header
Authorization: Basic base64(username:password). - Il n'y a aucun chiffrement par lui-même, d'ou l'usage obligatoire de HTTPS.
- Le serveur decode, vérifie les credentials, et applique les roles.
Point clé a retenir : l'authentification est gérée par Quarkus. Ton code metier ne doit jamais manipuler les identifiants ou mots de passe. C'est un principe de base en sécurité : l'application expose des routes et des roles, l'infrastructure de sécurité gère l'identité.
Utilisateurs embarques (embedded user)
Premier rempart : une serrure simple, directe, avec des utilisateurs declares dans application.properties. C'est ideal pour un prototype ou un donjon d'entrainement.
Les dépendances
Pour sécuriser l’API avec une authentification simple, deux dépendances sont nécessaires :
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-properties-file</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security</artifactId>
</dependency>les dépendances qui seront utilisées
quarkus-security: Cette dépendance constitue le socle de la sécurité dans Quarkus.
Elle active les mécanismes de base : gestion des identités, rôles, et intégration avec les annotations de sécurité (@RolesAllowed, etc.).
Autrement dit, elle fournit l’infrastructure nécessaire pour protéger les endpoints.quarkus-elytron-security-properties-file: Cette extension permet de définir des utilisateurs directement dans des fichiers de configuration (application.propertiesou fichiers dédiés).
Elle repose sur Elytron, le moteur de sécurité utilisé par Quarkus, et offre une solution simple pour déclarer des utilisateurs / associer des mots de passe / définir des rôles.
Les properties
Configuration dans application.properties :
# Basic Auth avec utilisateurs embarques
quarkus.http.auth.basic=true
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.keeper=keeper123
quarkus.security.users.embedded.roles.keeper=keeper
quarkus.security.users.embedded.users.supplier=supplier123
quarkus.security.users.embedded.roles.supplier=supplier
les properties
Mais concrètement, que font elles ?
quarkus.http.auth.basic=true- Active l’authentification Basic Auth au niveau HTTP
- Sans cette propriété, aucune authentification n’est appliquée
- Si le header
Authorizationest absent ou invalide → réponse401 Unauthorized
quarkus.security.users.embedded.enabled=true- Active un Identity Provider embarqué basé sur la configuration
- Les utilisateurs sont définis directement dans
application.properties - Aucun besoin de base de données
- Idéal pour du test ou du prototypage
quarkus.security.users.embedded.plain-text=true- Autorise les mots de passe en clair (⚠️ À utiliser uniquement en développement)
quarkus.security.users.embedded.users.keeper=keeper123 quarkus.security.users.embedded.users.supplier=supplier123- Déclare les utilisateurs et leurs mots de passe
- Format :
users.<username>=<password>
quarkus.security.users.embedded.roles.keeper=keeper quarkus.security.users.embedded.roles.supplier=supplier- Associe des rôles aux utilisateurs
- Format :
roles.<username>=<role1>,<role2>
- Ces rôles sont utilisés dans le code avec
@RolesAllowed
L'API
Les endpoints du cellier et de la reserve sont proteges via des roles :
@Path("/api/tavern")
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "Tavern Stock", description = "Acces a la reserve de nourriture et de biere.")
@SecurityScheme(securitySchemeName = "basicAuth", type = SecuritySchemeType.HTTP, scheme = "basic")
@SecurityRequirement(name = "basicAuth")
public class PantryResource {
private final PantryService pantryService;
@Inject
public PantryResource(PantryService pantryService) {
this.pantryService = pantryService;
}
@GET
@Path("/pantry")
@RolesAllowed("keeper")
@Operation(summary = "Reserve de nourriture", description = "Liste le contenu de la reserve.")
@APIResponse(
responseCode = "200",
description = "Contenu de la reserve",
content = @Content(schema = @Schema(implementation = StockResponse.class))
)
public StockResponse pantry() {
return pantryService.pantry();
}
@GET
@Path("/cellar")
@RolesAllowed({"keeper", "supplier"})
@Operation(summary = "Cave a biere", description = "Liste le contenu de la cave.")
@APIResponse(
responseCode = "200",
description = "Contenu de la cave",
content = @Content(schema = @Schema(implementation = StockResponse.class))
)
public StockResponse cellar() {
return pantryService.cellar();
}
}notre API
Tests rapides :


En bref : rapide a mettre en place, ideal pour des environnements de test ou de demo.
Utilisateurs stockes en base via JDBC
Quand la taverne grandit, la simple serrure du cellier ne suffit plus.
Il faut un contrôle plus rigoureux : vérifier précisément qui entre, et sur quelle base.
Les accès ne sont plus définis à la main, mais reposent désormais sur une source fiable et centralisée : une base de données.
Le cellier reste le même… mais la manière de contrôler son accès devient plus solide.
Ici, Quarkus s’appuie sur Elytron JDBC pour aller vérifier les identités directement en base.
Les dépendances
Pour activer l’authentification via une base de données, on utilise l’extension JDBC de sécurité :
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-jdbc</artifactId>
</dependency>les dépendances à utilisées
Elle vient compléter le socle quarkus-security déjà présent.
quarkus-security: fournit l’infrastructure de sécurité (identité, rôles, annotations)quarkus-elytron-security-jdbc: permet d’interroger une base de données pour authentifier les utilisateurs
Les properties
Configuration dans application.properties :
quarkus.http.auth.basic=true
quarkus.datasource.db-kind=h2
quarkus.datasource.username=sa
quarkus.datasource.password=sa
quarkus.datasource.jdbc.url=jdbc:h2:mem:tavern-security;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:db/init.sql'
quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=SELECT u.password, u.role FROM tavern_user u WHERE u.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.attribute-mappings.0.index=2
quarkus.security.jdbc.principal-query.attribute-mappings.0.to=groups
# Swagger UI accessible sans authentification
quarkus.http.auth.permission.swagger-ui.paths=/q/swagger-ui/*,/q/openapi
quarkus.http.auth.permission.swagger-ui.policy=permit
# API taverne protegees
quarkus.http.auth.permission.tavern.paths=/api/tavern/*
quarkus.http.auth.permission.tavern.policy=authenticatedles properties
Mais concrètement, que font-elles ?
quarkus.http.auth.basic=true- Active l’authentification Basic Auth
- Comme précédemment, sans cette propriété → aucune sécurité appliquée
quarkus.datasource.db-kind=h2- Définit le type de base de données (ici H2 en mémoire)
quarkus.datasource.jdbc.url=...- Configure la connexion à la base
- Initialise automatiquement le schéma et les données via un script SQL
quarkus.datasource.username / password- Identifiants d’accès à la base
quarkus.security.jdbc.enabled=true- Active l’Identity Provider basé sur JDBC
quarkus.security.jdbc.principal-query.sql=...- Requête exécutée pour authentifier un utilisateur
- Elle doit retourner :
- le mot de passe
- les rôles
clear-password-mapper- Indique que le mot de passe est stocké en clair (⚠️ uniquement pour démo)
password-index=1→ position du mot de passe dans le résultat SQL
attribute-mappings- Permet de mapper les colonnes vers les rôles
index=2→ colonne contenant le rôleto=groups→ correspond aux rôles utilisés par@RolesAllowed
Les données
Les utilisateurs ne sont plus définis dans les properties, mais directement en base :
CREATE TABLE tavern_user (
id INT PRIMARY KEY,
username VARCHAR(255),
password VARCHAR(255),
role VARCHAR(255)
);
INSERT INTO tavern_user (id, username, password, role) VALUES (1, 'keeper', 'keeper123', 'keeper');
INSERT INTO tavern_user (id, username, password, role) VALUES (2, 'supplier', 'supplier123', 'supplier');le script d'initialisation de la base de données
L’API
Rien ne change côté endpoints.
Les règles d’accès restent définies par les rôles avec @RolesAllowed.
Seule la source d’identité évolue : elle est désormais externalisée en base.
En bref
Une approche simple et robuste :
les utilisateurs sont centralisés, accessibles, et facilement maintenables.
Parfaite lorsque la taverne commence à accueillir du monde…
mais sans encore nécessiter toute la richesse d’un modèle objet complet.
Utilisateurs stockés via JPA
Dernier niveau de défense : un contrôle d’accès entièrement intégré au fonctionnement de la taverne.
Le cellier n’est plus simplement protégé par une vérification externe.
Les règles d’accès font désormais partie du système lui-même, avec des identités structurées, sécurisées et prêtes à évoluer.
On ne se contente plus de vérifier qui entre :
on modélise et on sécurise durablement les accès au cellier.
Les dépendances
Pour activer cette approche, on utilise l’extension dédiée :
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa</artifactId>
</dependency>la dépendance pour la sécurité avec JPA
Elle s’appuie sur JPA pour gérer les utilisateurs comme des entités.
quarkus-security: socle de la sécurité (identité, rôles, annotations)quarkus-security-jpa: permet de déléguer l’authentification à des entités JPA
L’entité utilisateur
Les utilisateurs sont désormais définis comme une entité persistée :
@Entity
@UserDefinition
public class TavernUser extends PanacheEntity {
@Username
public String username;
@Password
public String password;
@Roles
public Set<String> roles;
}notre model pour les utilisateur
Mais concrètement, que font ces annotations ?
@UserDefinition- Indique que cette entité représente un utilisateur de sécurité
@Username- Champ utilisé comme identifiant de connexion
@Password- Champ contenant le mot de passe (hashé)
@Roles- Définit les rôles associés à l’utilisateur
Ici, Quarkus fait le lien automatiquement entre le modèle JPA et le moteur de sécurité.
Initialisation des utilisateurs
Les comptes sont créés au démarrage de l’application :
TavernUser keeper = new TavernUser();
keeper.username = "keeper";
keeper.password = BcryptUtil.bcryptHash("keeper123");
keeper.roles = Set.of("keeper");
keeper.persist();
TavernUser supplier = new TavernUser();
supplier.username = "supplier";
supplier.password = BcryptUtil.bcryptHash("supplier123");
supplier.roles = Set.of("supplier");
supplier.persist();Contrairement aux approches précédentes :
- les mots de passe sont hashés avec bcrypt
- les utilisateurs sont manipulés comme de vrais objets métier
Les properties
Configuration dans application.properties :
quarkus.http.auth.basic=true
quarkus.datasource.db-kind=h2
quarkus.datasource.username=sa
quarkus.datasource.password=sa
quarkus.datasource.jdbc.url=jdbc:h2:mem:tavern-security-jpa;DB_CLOSE_DELAY=-1
quarkus.hibernate-orm.database.generation=drop-and-createles properties
quarkus.datasource.*- Configure la base de données (ici H2 en mémoire)
quarkus.hibernate-orm.database.generation=drop-and-create- Génère automatiquement le schéma à partir des entités
- Réinitialise la base à chaque démarrage (pratique en dev)
L’API
Aucun changement côté endpoints.
Les règles d’accès restent définies via @RolesAllowed.
Seule la manière de gérer les identités évolue : elles sont maintenant intégrées au modèle applicatif.
Limites de Basic Auth
Basic Auth remplit parfaitement son rôle pour démarrer, mais il montre rapidement ses limites :
- pas de véritable mécanisme de déconnexion (les credentials sont souvent conservés par le navigateur)
- identifiants envoyés à chaque requête
- peu adapté aux applications modernes (SPA, mobile)
- à proscrire sans HTTPS
Dès que la taverne s’ouvre au public ou prend de l’ampleur, il devient nécessaire d’adopter des solutions plus solides, comme les systèmes à base de tokens (OAuth2, OIDC).
Conclusion
Du simple verrou posé sur une porte jusqu’au registre soigneusement tenu, voire au grimoire protégé, le cellier de la taverne est désormais sous bonne garde.
Avec Quarkus, la sécurité se met en place par couches, sans complexité inutile : tu définis les rôles, les accès, et le moteur fait le reste.
Qu’il s’agisse d’utilisateurs embarqués, d’une base JDBC ou d’un modèle JPA, l’essentiel reste le même : séparer clairement l’identité du code métier.
Et si un roublard tente malgré tout de forcer l’entrée, il trouvera porte close.
Prochaine étape : renforcer encore la défense, et abandonner les serrures visibles pour des mécanismes plus discrets et plus robustes.
Tout le code relatif à cet article peut être consulter ici :