Support AND logic for multiple security schemes in AsyncAPI 3.x
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
- Use only one $ref and describe the second requirement in description Pros: Spec-compliant Cons: Not machine-enforceable, tooling cannot validate
- 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:
- Array of $refs array.
security:
- - $ref: '#/components/securitySchemes/saslScram'
- $ref: '#/components/securitySchemes/mtls'
- 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.
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.
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.
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:
-
Getting back the
Security Requirement Objectin backward compatible way into AsyncAPI 3.x would be tooling a nightmare. We'd end up withSecurity Scheme | Reference Object | Security Requirement Objectmixing implicit and explicit connections. Keys incomponents.securitySchemeswill become significant again. We have to guarantee there is no ambiguity betweenSecurity SchemeandSecurity Requirementobjects. I like this option the most, but only in context that we'd like to replaceSecurity Scheme | Reference Object | Security Requirement ObjectbySecurity Requirement Objectin future. -
Continuing
Security Scheme | Reference Objectand 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']
- Do nothing, wait for 4.x and re-introduce
Security Requirement Objectin 4.x (when it comes)
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.
@derberg what do you think???