skip to content

In an OpenAPI document, what is the difference between two schemes in one security requirement object versus two objects?

level: middleimportance: should knowfreq 45%

answer

  1. One field, two levels of nesting
  2. Map keys behave one way
  3. Array elements behave the other
  4. One dash of YAML changes the meaning
  5. The trailing empty list is mandatory

basics

~20 s

Two schemes inside one OpenAPI security requirement object mean AND — the caller must satisfy both. Two requirement objects in the security array are alternatives, meaning OR — satisfying any one of them authorizes the request.

solid answer

~50 s

A `security` value is an **array of Security Requirement Objects**, and each object is a **map** from scheme name to a scope array. The two levels carry different logic. Within one object, every named scheme must be satisfied — that is AND, and it is how you express "an API key *and* a bearer token". Across the array, the entries are alternatives — that is OR, and only one needs to be satisfied. So one object holding two keys demands both credentials, while two single-key objects accept either. Every name used must exist in `components.securitySchemes`. The scope array carries meaning only for `oauth2` and `openIdConnect` schemes; OpenAPI 3.0 requires it to be empty for all other types, and 3.1 relaxed that to allow role names the specification leaves undefined and that are not exchanged in-band.

code

yaml · 18 lines
yaml
# Both credentials required (AND)
security:
  - apiKeyAuth: []
    bearerAuth: []

---
# Either credential accepted (OR)
security:
  - apiKeyAuth: []
  - bearerAuth: []

---
# OAuth2 alternative carrying scopes, or a legacy key
security:
  - petstoreOauth:
      - read:pets
      - write:pets
  - apiKeyAuth: []

go deeper

for a junior

Know that security is a list and each entry names one or more schemes, with the empty array after each name being required syntax.

for a middle

Explain the AND/OR distinction precisely from the YAML nesting, and state which scheme types may carry scope names in the array.

for a senior

Show that you verify the resolved requirement in a renderer rather than reading nesting by eye, and that you check what generated SDKs make of alternatives before publishing them.

for a principal

Own whether the platform expresses migration windows as OR alternatives in the contract at all, and how long a legacy credential stays documented before removal.

## Two nested structures, two operators This question is really about reading YAML precisely. The `security` field takes an **array**. Each element of that array is a **Security Requirement Object**, which is a **map** whose keys are names defined in `components.securitySchemes`. - **Keys within one object → AND.** All of them must be satisfied. - **Objects within the array → OR.** Any one of them satisfies the requirement. In YAML the distinction is one dash: a single-element array holding a two-key map means both credentials, while a two-element array of single-key maps means either. In JSON the difference is obvious — one object with two properties versus two objects with one property each — which is a decent argument for reviewing security blocks in the JSON rendering when a document is large. ## When AND is the right answer The combination genuinely occurs. A partner API may require a per-organisation API key identifying the calling integration *plus* a bearer token identifying the end user, because the two credentials answer different questions. Gateway deployments sometimes require a gateway key alongside the service's own token. In those cases both belong in one requirement object. AND is not the right way to express "a token with two scopes" — scopes are listed inside the single oauth2 entry's array, not by naming the scheme twice. ## When OR is the right answer Alternatives are the more common case: the same operation accepts a session cookie from the web app or a bearer token from the mobile client; a service accepts an OAuth2 access token or a legacy API key during a migration window. Listing alternatives documents the migration honestly and lets generated clients and documentation offer both. ## The scope array Every entry's value is an array, even when empty, and the empty array is not decoration — it is the required form. What may go inside depends on the scheme's type: - For **`oauth2`** and **`openIdConnect`**, the array lists the scope names required to execute the operation. Those names must be among the ones the scheme declares (for oauth2, in its flows' `scopes` maps). - For **every other type**, OpenAPI **3.0** states the array MUST be empty. OpenAPI **3.1** relaxed this: the array MAY contain role names, but the specification explicitly does not define them and they are not exchanged in-band — meaning no tool does anything with them, and they are documentation at best. So an empty array after a bearer scheme's name is correct in both versions, and putting `admin` there is invalid in 3.0 and inert in 3.1. Writing scope names against a bearer scheme is a common way of trying to express authorization in the document; it does not work, and the honest place for that information is the operation's `description` or an oauth2 scheme with real scopes. ## Validation and tooling behaviour Every key must resolve to a defined scheme; a typo produces an invalid document that most linters catch. Documentation renderers show alternatives as separate options and combined requirements as a group. Client generators handle OR imperfectly — several will pick one alternative or expose all credentials as optional constructor arguments, leaving the caller to know which combination works. That practical weakness is worth mentioning in an interview: expressing OR in the document is correct, but it does not guarantee the generated SDK expresses the choice cleanly. ## The failure this prevents The defect this question targets is a document that means AND while the team believes it means OR, or the reverse. In the OR-meant-AND direction, generated clients and mock validators demand two credentials and callers cannot get through. In the AND-meant-OR direction, the document understates what the API requires, and an integrator builds against a spec that says one credential suffices. Neither is caught by schema validation, because both forms are structurally valid — only reading the nesting carefully, or checking a resolved view in a renderer, catches it.

  • What may the scope array contain for a scheme of type apiKey?
    In OpenAPI 3.0 it must be empty — the specification is explicit. OpenAPI 3.1 relaxed the rule to allow role names, while stating they are not otherwise defined or exchanged in-band, so no tooling acts on them. Practically, write an empty array for apiKey, http and mutualTLS schemes; scope lists are meaningful only for oauth2 and openIdConnect.
  • How do you express that an operation needs two oauth2 scopes?
    List both inside that scheme's array in a single requirement object, so the entry names the scheme once with two scope names under it. Both scopes are then required together. You do not name the scheme twice or split it across requirement objects, since a second object would create an alternative rather than an additional requirement.
  • Do generated clients handle OR alternatives well?
    Often not. Several generators pick one alternative, or expose every credential as an optional argument and leave the caller to discover which combination the server accepts. The document is still correct — expressing alternatives honestly is right — but it is worth checking the generated SDK for the languages you publish rather than assuming the choice survives code generation.

saying these in an interview costs you the question

  • Reads a two-key requirement object as alternatives
  • Puts scope names against a bearer or apiKey scheme
  • Thinks the empty array is optional decoration
  • Names a scheme twice to require two scopes
  • References a scheme name not defined in components

context