Source profileQuality 74/100

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

quarkus-security

Use it for data analysis tasks; the detail page covers purpose, installation, and practical steps.

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

認証、認可、入力検証によってQuarkusアプリケーションを保護するためのベストプラクティス。

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/ja-JP/skills/quarkus-security"
    Safe inspection promptEditorial

    Inspect the Agent Skill "quarkus-security" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/ja-JP/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

      When to Activate

      認証追加(JWT、OIDC、Basic認証)

      認証追加(JWT、OIDC、Basic認証)@RolesAllowedまたはSecurityIdentityで認可実装ユーザー入力検証(Bean Validation、カスタムバリデータ)
    2. 02

      Authentication

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

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

      JWT Authentication

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

      Configuration (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

      Custom Authentication Filter

      Review the “Custom Authentication Filter” section in the pinned source before continuing.

      Review and apply the “Custom Authentication Filter” 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 score74/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/ja-JP/skills/quarkus-security/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Quarkus Security Review

    認証、認可、入力検証によってQuarkusアプリケーションを保護するためのベストプラクティス。

    When to Activate

    • 認証追加(JWT、OIDC、Basic認証)
    • @RolesAllowedまたはSecurityIdentityで認可実装
    • ユーザー入力検証(Bean Validation、カスタムバリデータ)
    • CORS設定またはセキュリティヘッダー構成
    • シークレット管理(Vault、環境変数、設定ソース)
    • レート制限またはブルートフォース対策追加
    • CVEの依存関係スキャン
    • MicroProfile JWTまたはSmallRye JWT操作

    Authentication

    JWT Authentication

    // 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();
      }
    }
    

    Configuration (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}
    

    Custom Authentication Filter

    @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;
      }
    }
    

    Authorization

    Role-Based Access Control

    @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();
      }
    
      private boolean isOwner(Long userId, String username) {
        return userService.isOwner(userId, username);
      }
    }
    

    Programmatic Security

    @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);
      }
    }
    

    Input Validation

    Bean Validation

    // 悪い例:検証なし
    @POST
    public Response createUser(UserDto dto) {
      return Response.ok(userService.create(dto)).build();
    }
    
    // 良い例:検証DTO
    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();
    }
    

    Custom Validators

    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = UsernameValidator.class)
    public @interface ValidUsername {
      String message() default "Invalid username format";
      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}$");
      }
    }
    
    // 使用例
    public record CreateUserDto(
        @ValidUsername String username,
        @NotBlank @Email String email
    ) {}
    

    SQL Injection Prevention

    Panache Active Record (Safe by Default)

    // 良い例:Panacheでのパラメータ化クエリ
    List<User> users = User.list("email = ?1 and active = ?2", email, true);
    
    Optional<User> user = User.find("username", username).firstResultOptional();
    
    // 良い例:名前付きパラメータ
    List<User> users = User.list("email = :email and age > :minAge",
        Parameters.with("email", email).and("minAge", 18));
    

    Native Queries (Use Parameters)

    // 悪い例:文字列連結
    @Query(value = "SELECT * FROM users WHERE name = '" + name + "'", nativeQuery = true)
    
    // 良い例:パラメータ化ネイティブクエリ
    @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();
      }
    }
    

    Password Hashing

    @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);
      }
    }
    
    // サービスで使用
    @ApplicationScoped
    public class UserService {
      @Inject
      PasswordService passwordService;
    
      @Transactional
      public User register(CreateUserDto dto) {
        String hashedPassword = passwordService.hash(dto.password());
        User user = new User();
        user.email = dto.email();
        user.password = hashedPassword;
        user.persist();
        return user;
      }
    
      public boolean authenticate(String email, String password) {
        return User.find("email", email)
            .firstResultOptional()
            .map(u -> passwordService.verify(password, u.password))
            .orElse(false);
      }
    }
    

    CORS Configuration

    # 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.exposed-headers=Content-Disposition
    quarkus.http.cors.access-control-max-age=24H
    quarkus.http.cors.access-control-allow-credentials=true
    

    Secrets Management

    # application.properties - シークレットはここに置かない
    
    # 環境変数を使用
    quarkus.datasource.username=${DB_USER}
    quarkus.datasource.password=${DB_PASSWORD}
    quarkus.oidc.credentials.secret=${OIDC_CLIENT_SECRET}
    
    # またはVaultを使用
    quarkus.vault.url=https://vault.example.com
    quarkus.vault.authentication.kubernetes.role=my-role
    

    HashiCorp Vault Integration

    @ApplicationScoped
    public class SecretService {
    
      @ConfigProperty(name = "api-key")
      String apiKey; // Vault から取得
    
      public String getSecret(String key) {
        return ConfigProvider.getConfig().getValue(key, String.class);
      }
    }
    

    Rate Limiting

    セキュリティ注意: X-Forwarded-For を直接使用しないでください — クライアントで偽装できます。 サーブレットリクエストからの実際のリモートアドレスを使用するか、利用可能な場合は認証ID(APIキー、JWTサブジェクト)を使用します。

    @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)); // 1秒あたり100リクエスト
    
        if (!limiter.tryAcquire()) {
          requestContext.abortWith(
              Response.status(429)
                  .entity(Map.of("error", "Too many requests"))
                  .build()
          );
        }
      }
    
      private String getClientIdentifier() {
        // コンテナが提供するリモートアドレスを使用(X-Forwarded-Forではない)
        // 信頼されたプロキシの背後にある場合、quarkus.http.proxy.proxy-address-forwarding=trueを設定して
        // getRemoteAddr()が実クライアントIPを返すようにします
        return servletRequest.getRemoteAddr();
      }
    }
    

    Security Headers

    @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");
    
        // XSS保護
        headers.putSingle("X-Content-Type-Options", "nosniff");
        headers.putSingle("X-XSS-Protection", "1; mode=block");
    
        // HSTS
        headers.putSingle("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
    
        // CSP — script-src用の'unsafe-inline'は避けてください。XSS保護を無効化します。
        // 代わりにnoncesまたはhashesを使用します。CSSフレームワークが必要な場合、
        // style-srcの'unsafe-inline'は許容ですが、可能な場合はnoncesを優先してください。
        headers.putSingle("Content-Security-Policy",
            "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");
      }
    }
    

    Audit Logging

    @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());
      }
    }
    
    // リソースでの使用
    @Path("/api/sensitive")
    public class SensitiveResource {
      @Inject
      AuditService auditService;
    
      @GET
      @RolesAllowed("ADMIN")
      public Response getData() {
        auditService.logAccess("sensitive-data", "READ");
        return Response.ok(data).build();
      }
    }
    

    Dependency Security Scanning

    # Maven
    mvn org.owasp:dependency-check-maven:check
    
    # Gradle
    ./gradlew dependencyCheckAnalyze
    
    # Quarkus拡張機能チェック
    quarkus extension list --installable
    

    Best Practices

    • 本番環境では常にHTTPSを使用
    • ステートレス認証にはJWTまたはOIDCを有効化
    • 宣言的認可に@RolesAllowedを使用
    • Bean Validationで全入力検証
    • BCryptでパスワードハッシュ化(プレーンテキスト厳禁)
    • VaultまたはLambda環境変数でシークレット保存
    • SQLインジェクション防止にパラメータ化クエリを使用
    • 全レスポンスにセキュリティヘッダー追加
    • 公開エンドポイントにレート制限実装
    • 機密操作を監査ログに記録
    • 依存関係を最新に保ちCVEスキャン実施
    • プログラム的チェックにSecurityIdentityを使用
    • 適切なCORSポリシー設定
    • 認証・認可経路をテスト

    Alternatives

    Compare before choosing