Skip to content

Support AND logic for multiple security schemes in AsyncAPI 3.x #1129

Open

Description

@rahmathm1

Problem

Currently, AsyncAPI 3.x only allows expressing OR semantics between multiple security schemes using the security array:

security:
  - $ref: '#/components/securitySchemes/saslScram'
  - $ref: '#/components/securitySchemes/mtls'

This means either SASL/SCRAM or mTLS can authorize a connection.
However, in many real-world scenarios, a server or operation may require multiple authentication schemes simultaneously (logical AND), for example:
SASL/SCRAM and a valid client certificate (mTLS) for a Kafka broker

Currently, there is no spec-compliant way to enforce both requirements in AsyncAPI 3.x without using a vendor extension (x- fields) or describing it only in prose. This limitation prevents full machine-readable documentation and automated validation of multi-factor authentication requirements.

Current workarounds

  1. Use only one $ref and describe the second requirement in description
    Pros: Spec-compliant
    Cons: Not machine-enforceable, tooling cannot validate
  2. Vendor extension
    Pros: Documents AND requirement
    Cons: Non-standard, tooling may ignore it
    Neither approach is ideal for consistent, spec-compliant multi-scheme security modeling.

Proposal

Introduce a native, spec-supported syntax to express AND logic between multiple security schemes in a single security requirement object. Possible approaches:

  1. Array of $refs array.
security:
  - - $ref: '#/components/securitySchemes/saslScram'
    - $ref: '#/components/securitySchemes/mtls'
  1. Named keys with logical AND semantics (similar to v2):
security:
  - saslScram: []
    mtls: []

Requirements for tooling: Studio, CLI validator, and generators should enforce that all schemes in a single requirement object are required.

Activity

  1. github-actions commented on Oct 23, 2025

    @github-actions

    Welcome to AsyncAPI. Thanks a lot for reporting your first issue. Please check out our contributors guide and the instructions about a basic recommended setup useful for opening a pull request.
    Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out this issue.

  2. rahmathm1 commented on Oct 24, 2025

    @rahmathm1
    Author

    The approaches shared above are still in a preliminary state and shouldn’t be considered formal proposals. I don’t have a finalized approach yet, but I'm actively working on it and will provide an update here soon.

  3. char0n commented on Dec 11, 2025

    @char0n
    Member

    Hi everybody,

    Some of my thoughts after research:

    We haven't had this problem in AsyncAPI 2.x. We had a Security Requirement Object which was creating implicit connection with Security Scheme Objects. This naturally allowed logical disjunctions (OR) and conjunctions (AND). This was aligned with how OpenAPI works (discussion about it in this issue).

    In AsyncAPI 3.0, Security Requirement Object was dropped and replaced by union of Security Scheme | Reference Object. I'm not sure about the reason, but this change made the logical disjunctions the only allowed mechanism. I assume the motivation might have been to remove implicit connection and make the connection explicit? Or make everything referencable? I can only guess...

    Now the question is if we want to return back to Security Requirement object, which is well known, established and battle tested concept, or continue with explicit union of Security Scheme | Reference Object and use nested arrays to express logical groupings.

    We have couple of options:

    1. Getting back the Security Requirement Object in backward compatible way into AsyncAPI 3.x would be tooling a nightmare. We'd end up with Security Scheme | Reference Object | Security Requirement Object mixing implicit and explicit connections. Keys in components.securitySchemes will become significant again. We have to guarantee there is no ambiguity between Security Scheme and Security Requirement objects. I like this option the most, but only in context that we'd like to replace Security Scheme | Reference Object | Security Requirement Object by Security Requirement Object in future.

    2. Continuing Security Scheme | Reference Object and using nested array to express logical groupings. I might be appropriate to break [Security Scheme Object | Reference Object] | [[Security Scheme Object | Reference Object]] into sub-types for people to be able to make sense of it:

    Securities = [Security Scheme Object | Reference Object]
    
    security: Securities | [Securities]
    

    Also noting that YAML syntax looks unnatural (even though it's completely valid):

    security:
      - - $ref: '#/components/securitySchemes/saslScram'
        - $ref: '#/components/securitySchemes/mtls'
    

    I'd go for flow style here (to describe this in examples) which is equivalent with above but more comprehendable:

    security:
      - [$ref: '#/components/securitySchemes/saslScram', $ref: '#/components/securitySchemes/mtls']
    
    1. Do nothing, wait for 4.x and re-introduce Security Requirement Object in 4.x (when it comes)
  4. moved this to Todo in Spec Triageon Dec 12, 2025
  5. moved this from Todo to In Progress in Spec Triageon Dec 12, 2025
  6. RUTUPARNk commented on Dec 18, 2025

    @RUTUPARNk

    This is a real limitation I’ve run into when trying to model production setups, especially for Kafka-based systems where brokers commonly require multiple authentication mechanisms simultaneously (e.g., mTLS for transport identity + SASL/SCRAM for client auth).

    Today the security array only allows OR semantics, which makes these configurations either:

    under-specified (described only in prose), or

    vendor-specific (via x-* extensions), both of which reduce tooling usefulness.

    I’m generally in favor of introducing explicit AND semantics at the spec level. Between the options discussed, the nested array approach feels the most explicit and least ambiguous:

    security:

    - $ref: '#/components/securitySchemes/saslScram'
    - $ref: '#/components/securitySchemes/mtls'
    

    This preserves backward compatibility, makes OR vs AND visually obvious, and aligns well with how tooling already treats the outer array as a disjunction.

    One question I have is around mixed logic clarity — e.g., multiple AND-groups combined with OR:

    security:

    • [saslScram, mtls]
    • [oauth2]

    If this interpretation is intended (“(SASL AND mTLS) OR OAuth2”), it might be worth explicitly documenting this precedence to avoid confusion for tooling implementers.

    Happy to help further by drafting schema changes, examples, or validator updates once a direction is agreed.

  7. RUTUPARNk commented on Dec 19, 2025

    @RUTUPARNk

    @derberg what do you think???

  8. derberg commented on Jan 27, 2026

    @derberg
    Member

    link to the last meeting recording where we discussed the topic of breaking change: https://www.youtube.com/watch?v=pvZcbln80ak

  9. derberg commented on Mar 26, 2026

    @derberg
    Member

    latest update: #1135 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions