Source profileQuality 76/100

affaan-m/ECC/docs/es/skills/quarkus-security/SKILL.md

quarkus-security

Buenas prácticas de seguridad en Quarkus para autenticación, autorización, JWT/OIDC, RBAC, validación de entrada, CSRF, gestión de secretos y seguridad de dependencias.

Source repository stars
234,327
Declared platforms
0
Static risk flags
1
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

Buenas prácticas para asegurar aplicaciones Quarkus con autenticación, autorización y validación de entrada.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/quarkus-security"
    Safe inspection promptEditorial

    Inspect the Agent Skill "quarkus-security" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/es/skills/quarkus-security/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Cuándo Activar

      Agregar autenticación (JWT, OIDC, Basic Auth)

      Agregar autenticación (JWT, OIDC, Basic Auth)Implementar autorización con @RolesAllowed o SecurityIdentityValidar entrada de usuario (Bean Validation, validadores personalizados)
    2. 02

      Autenticación

      Configuración (application.properties): properties mp.jwt.verify.publickey.location=publicKey.pem mp.jwt.verify.issuer=https://auth.example.com

      Configuración (application.properties): properties mp.jwt.verify.publickey.location=publicKey.pem mp.jwt.verify.issuer=https://auth.example.com
    3. 03

      Autenticación JWT

      Configuración (application.properties): properties mp.jwt.verify.publickey.location=publicKey.pem mp.jwt.verify.issuer=https://auth.example.com

      Configuración (application.properties): properties mp.jwt.verify.publickey.location=publicKey.pem mp.jwt.verify.issuer=https://auth.example.com
    4. 04

      OIDC

      quarkus.oidc.auth-server-url=https://auth.example.com/realms/myrealm quarkus.oidc.client-id=backend-service quarkus.oidc.credentials.secret=${OIDCSECRET} java @Provider @Priority(Priorities.AUTHENTICATION) public class CustomAuthFilter implements ContainerRequestFilter {

      quarkus.oidc.auth-server-url=https://auth.example.com/realms/myrealm quarkus.oidc.client-id=backend-service quarkus.oidc.credentials.secret=${OIDCSECRET} java @Provider @Priority(Priorities.AUTHENTICATION) public class…@Inject SecurityIdentity identity;@Override public void filter(ContainerRequestContext requestContext) { String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
    5. 05

      Filtro de Autenticación Personalizado

      Review the “Filtro de Autenticación Personalizado” section in the pinned source before continuing.

      Review and apply the “Filtro de Autenticación Personalizado” source section.

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 48

    The documentation includes network, browsing, or remote request actions.

    mp.jwt.verify.issuer=https://auth.example.com

    Network access

    medium · line 51

    The documentation includes network, browsing, or remote request actions.

    quarkus.oidc.auth-server-url=https://auth.example.com/realms/myrealm

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score76/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/es/skills/quarkus-security/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Revisión de Seguridad Quarkus

    Buenas prácticas para asegurar aplicaciones Quarkus con autenticación, autorización y validación de entrada.

    Cuándo Activar

    • Agregar autenticación (JWT, OIDC, Basic Auth)
    • Implementar autorización con @RolesAllowed o SecurityIdentity
    • Validar entrada de usuario (Bean Validation, validadores personalizados)
    • Configurar CORS o cabeceras de seguridad
    • Gestionar secretos (Vault, variables de entorno, fuentes de configuración)
    • Agregar limitación de velocidad o protección contra fuerza bruta
    • Escanear dependencias por CVEs
    • Trabajar con MicroProfile JWT o SmallRye JWT

    Autenticación

    Autenticación JWT

    // Recurso protegido con JWT
    @Path("/api/protected")
    @Authenticated
    public class ProtectedResource {
    
      @Inject
      JsonWebToken jwt;
    
      @Inject
      SecurityIdentity securityIdentity;
    
      @GET
      public Response getData() {
        String username = jwt.getName();
        Set<String> roles = jwt.getGroups();
        return Response.ok(Map.of(
            "username", username,
            "roles", roles,
            "principal", securityIdentity.getPrincipal().getName()
        )).build();
      }
    }
    

    Configuración (application.properties):

    mp.jwt.verify.publickey.location=publicKey.pem
    mp.jwt.verify.issuer=https://auth.example.com
    
    # OIDC
    quarkus.oidc.auth-server-url=https://auth.example.com/realms/myrealm
    quarkus.oidc.client-id=backend-service
    quarkus.oidc.credentials.secret=${OIDC_SECRET}
    

    Filtro de Autenticación Personalizado

    @Provider
    @Priority(Priorities.AUTHENTICATION)
    public class CustomAuthFilter implements ContainerRequestFilter {
    
      @Inject
      SecurityIdentity identity;
    
      @Override
      public void filter(ContainerRequestContext requestContext) {
        String authHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
    
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
          requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
          return;
        }
    
        String token = authHeader.substring(7);
        if (!validateToken(token)) {
          requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }
      }
    
      private boolean validateToken(String token) {
        return true;
      }
    }
    

    Autorización

    Control de Acceso Basado en Roles

    @Path("/api/admin")
    @RolesAllowed("ADMIN")
    public class AdminResource {
    
      @GET
      @Path("/users")
      public List<UserDto> listUsers() {
        return userService.findAll();
      }
    
      @DELETE
      @Path("/users/{id}")
      @RolesAllowed({"ADMIN", "SUPER_ADMIN"})
      public Response deleteUser(@PathParam("id") Long id) {
        userService.delete(id);
        return Response.noContent().build();
      }
    }
    
    @Path("/api/users")
    public class UserResource {
    
      @Inject
      SecurityIdentity securityIdentity;
    
      @GET
      @Path("/{id}")
      @RolesAllowed("USER")
      public Response getUser(@PathParam("id") Long id) {
        if (!securityIdentity.hasRole("ADMIN") &&
            !isOwner(id, securityIdentity.getPrincipal().getName())) {
          return Response.status(Response.Status.FORBIDDEN).build();
        }
        return Response.ok(userService.findById(id)).build();
      }
    }
    

    Seguridad Programática

    @ApplicationScoped
    public class SecurityService {
    
      @Inject
      SecurityIdentity securityIdentity;
    
      public boolean canAccessResource(Long resourceId) {
        if (securityIdentity.isAnonymous()) {
          return false;
        }
    
        if (securityIdentity.hasRole("ADMIN")) {
          return true;
        }
    
        String userId = securityIdentity.getPrincipal().getName();
        return resourceRepository.isOwner(resourceId, userId);
      }
    }
    

    Validación de Entrada

    Bean Validation

    // MAL: Sin validación
    @POST
    public Response createUser(UserDto dto) {
      return Response.ok(userService.create(dto)).build();
    }
    
    // BIEN: DTO validado
    public record CreateUserDto(
        @NotBlank @Size(max = 100) String name,
        @NotBlank @Email String email,
        @NotNull @Min(18) @Max(150) Integer age,
        @Pattern(regexp = "^\\+?[1-9]\\d{1,14}$") String phone
    ) {}
    
    @POST
    @Path("/users")
    public Response createUser(@Valid CreateUserDto dto) {
      User user = userService.create(dto);
      return Response.status(Response.Status.CREATED).entity(user).build();
    }
    

    Validadores Personalizados

    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = UsernameValidator.class)
    public @interface ValidUsername {
      String message() default "Formato de nombre de usuario inválido";
      Class<?>[] groups() default {};
      Class<? extends Payload>[] payload() default {};
    }
    
    public class UsernameValidator implements ConstraintValidator<ValidUsername, String> {
      @Override
      public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) return false;
        return value.matches("^[a-zA-Z0-9_-]{3,20}$");
      }
    }
    

    Prevención de Inyección SQL

    Panache Active Record (Seguro por Defecto)

    // BIEN: Consultas parametrizadas con Panache
    List<User> users = User.list("email = ?1 and active = ?2", email, true);
    
    Optional<User> user = User.find("username", username).firstResultOptional();
    
    // BIEN: Parámetros nombrados
    List<User> users = User.list("email = :email and age > :minAge",
        Parameters.with("email", email).and("minAge", 18));
    

    Consultas Nativas (Usar Parámetros)

    // MAL: Concatenación de cadenas
    @Query(value = "SELECT * FROM users WHERE name = '" + name + "'", nativeQuery = true)
    
    // BIEN: Consulta nativa parametrizada
    @Entity
    public class User extends PanacheEntity {
      public static List<User> findByEmailNative(String email) {
        return getEntityManager()
            .createNativeQuery("SELECT * FROM users WHERE email = :email", User.class)
            .setParameter("email", email)
            .getResultList();
      }
    }
    

    Hash de Contraseñas

    @ApplicationScoped
    public class PasswordService {
    
      public String hash(String plainPassword) {
        return BcryptUtil.bcryptHash(plainPassword);
      }
    
      public boolean verify(String plainPassword, String hashedPassword) {
        return BcryptUtil.matches(plainPassword, hashedPassword);
      }
    }
    

    Configuración de CORS

    # application.properties
    quarkus.http.cors=true
    quarkus.http.cors.origins=https://app.example.com,https://admin.example.com
    quarkus.http.cors.methods=GET,POST,PUT,DELETE
    quarkus.http.cors.headers=accept,authorization,content-type,x-requested-with
    quarkus.http.cors.access-control-allow-credentials=true
    

    Gestión de Secretos

    # application.properties - SIN SECRETOS AQUÍ
    
    # Usar variables de entorno
    quarkus.datasource.username=${DB_USER}
    quarkus.datasource.password=${DB_PASSWORD}
    quarkus.oidc.credentials.secret=${OIDC_CLIENT_SECRET}
    
    # O usar Vault
    quarkus.vault.url=https://vault.example.com
    quarkus.vault.authentication.kubernetes.role=my-role
    

    Limitación de Velocidad

    Nota de Seguridad: Nunca usar X-Forwarded-For directamente — los clientes pueden falsificarlo. Usar la dirección remota real de la solicitud servlet, o una identidad autenticada (clave API, subject del JWT) cuando esté disponible.

    @ApplicationScoped
    public class RateLimitFilter implements ContainerRequestFilter {
      private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
    
      @Inject
      HttpServletRequest servletRequest;
    
      @Override
      public void filter(ContainerRequestContext requestContext) {
        String clientId = getClientIdentifier();
        RateLimiter limiter = limiters.computeIfAbsent(clientId,
            k -> RateLimiter.create(100.0)); // 100 solicitudes por segundo
    
        if (!limiter.tryAcquire()) {
          requestContext.abortWith(
              Response.status(429)
                  .entity(Map.of("error", "Demasiadas solicitudes"))
                  .build()
          );
        }
      }
    
      private String getClientIdentifier() {
        // Usar la dirección remota provista por el contenedor (no X-Forwarded-For).
        // Si está detrás de un proxy confiable, configurar
        // quarkus.http.proxy.proxy-address-forwarding=true
        // para que getRemoteAddr() retorne la IP real del cliente.
        return servletRequest.getRemoteAddr();
      }
    }
    

    Cabeceras de Seguridad

    @Provider
    public class SecurityHeadersFilter implements ContainerResponseFilter {
    
      @Override
      public void filter(ContainerRequestContext request, ContainerResponseContext response) {
        MultivaluedMap<String, Object> headers = response.getHeaders();
    
        headers.putSingle("X-Frame-Options", "DENY");
        headers.putSingle("X-Content-Type-Options", "nosniff");
        headers.putSingle("X-XSS-Protection", "1; mode=block");
        headers.putSingle("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
        // CSP: evitar 'unsafe-inline' para script-src; usar nonces o hashes
        headers.putSingle("Content-Security-Policy",
            "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");
      }
    }
    

    Logging de Auditoría

    @ApplicationScoped
    public class AuditService {
      private static final Logger LOG = Logger.getLogger(AuditService.class);
    
      @Inject
      SecurityIdentity securityIdentity;
    
      public void logAccess(String resource, String action) {
        String user = securityIdentity.isAnonymous()
            ? "anonymous"
            : securityIdentity.getPrincipal().getName();
    
        LOG.infof("AUDIT: user=%s action=%s resource=%s timestamp=%s",
            user, action, resource, Instant.now());
      }
    }
    

    Escaneo de Seguridad de Dependencias

    # Maven
    mvn org.owasp:dependency-check-maven:check
    
    # Gradle
    ./gradlew dependencyCheckAnalyze
    
    # Verificar extensiones de Quarkus
    quarkus extension list --installable
    

    Buenas Prácticas

    • Siempre usar HTTPS en producción
    • Habilitar JWT u OIDC para autenticación sin estado
    • Usar @RolesAllowed para autorización declarativa
    • Validar toda entrada con Bean Validation
    • Hashear contraseñas con BCrypt (nunca texto plano)
    • Almacenar secretos en Vault o variables de entorno
    • Usar consultas parametrizadas para prevenir inyección SQL
    • Agregar cabeceras de seguridad a todas las respuestas
    • Implementar limitación de velocidad para endpoints públicos
    • Auditar operaciones sensibles
    • Mantener dependencias actualizadas y escanear por CVEs
    • Usar SecurityIdentity para verificaciones programáticas
    • Establecer políticas CORS apropiadas
    • Probar rutas de autenticación y autorización

    Alternatives

    Compare before choosing