-
Notifications
You must be signed in to change notification settings - Fork 287
Description
When building an OpenApiDocument programmatically and adding security requirements using OpenApiSecuritySchemeReference as dictionary keys in OpenApiSecurityRequirement, the serialized output produces "security": [{}] instead of "security": [{"Bearer": []}].
The root cause is in OpenApiSecurityRequirement.SerializeInternal(), which filters entries with:
this.Where(static p => p.Key?.Target is not null)When the document is constructed in memory (not parsed from a file), Target resolves via Reference.HostDocument.ResolveReferenceTo<U>(Reference, ...), which returns null because the security scheme was added to Components.SecuritySchemes as a plain OpenApiSecurityScheme, not as an IOpenApiSecurityScheme that the resolver can match. The filter silently drops the entry with no warning.
To Reproduce
using Microsoft.OpenApi;
var doc = new OpenApiDocument
{
Info = new OpenApiInfo { Title = "Test", Version = "1.0" },
Components = new OpenApiComponents
{
SecuritySchemes = new Dictionary<string, IOpenApiSecurityScheme>(StringComparer.Ordinal)
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT",
},
},
},
Security =
[
new OpenApiSecurityRequirement
{
{ new OpenApiSecuritySchemeReference("Bearer", doc), [] },
},
],
};
var json = await doc.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_2);
Console.WriteLine(json);Expected behavior
{
"security": [
{
"Bearer": []
}
]
}Actual behavior
{
"security": [
{}
]
}No exception or warning is produced — the entry is silently dropped.
Version
- Microsoft.OpenApi 2.0.0-preview17 (and later, including transitive via Microsoft.OpenApi.OData 3.2.0)
- Also affects 3.0 and 3.1 serialization — all three
SerializeAsV3/V31/V32methods share the sameSerializeInternalcode path.
Additional context
- This is a common scenario when using
Microsoft.OpenApi.ODatato generate an OpenAPI document from an EDM model and then adding security definitions programmatically. - Related to If securityScheme is a reference it cannot be resolved (see issue #1166, this issue still persists in V1.6.3) #1229, but this repro path is purely in-memory construction with no external files.
- Workaround: subclass
OpenApiSecurityRequirementand overrideSerializeAsV3/SerializeAsV31/SerializeAsV32to write the security scheme name directly viaIOpenApiWriter.
Suggested fix
The Where filter in SerializeInternal should fall back to Reference.ReferenceV3 (or Reference.Id) when Target is null, rather than silently skipping the entry. The callback already uses s.Reference.ReferenceV3 for the property name — the guard just needs to allow entries where the reference ID is available even if Target couldn't be resolved.