From 335cee5dece87d0be2060e0e5d494189734f9ba2 Mon Sep 17 00:00:00 2001
From: mdaneri <17148649+mdaneri@users.noreply.github.com>
Date: Thu, 22 Jan 2026 09:13:17 -0800
Subject: [PATCH 1/8] feat(securityscheme): add oauth2 metadata url support
---
.../Interfaces/IOpenApiSecurityScheme.cs | 6 ++
.../Models/OpenApiConstants.cs | 5 ++
.../Models/OpenApiSecurityScheme.cs | 9 +++
.../OpenApiSecuritySchemeReference.cs | 3 +
.../V32/OpenApiSecuritySchemeDeserializer.cs | 12 ++-
.../V32Tests/OpenApiSecuritySchemeTests.cs | 30 ++++++++
.../oauth2SecuritySchemeWithMetadataUrl.yaml | 8 ++
.../Models/OpenApiSecuritySchemeTests.cs | 73 +++++++++++++++++++
8 files changed, 145 insertions(+), 1 deletion(-)
create mode 100644 test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/oauth2SecuritySchemeWithMetadataUrl.yaml
diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs
index 41247ce08..16da4a881 100644
--- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs
+++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs
@@ -46,6 +46,12 @@ public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiRead
///
public Uri? OpenIdConnectUrl { get; }
+ ///
+ /// URL to the OAuth2 Authorization Server Metadata document (RFC 8414).
+ /// Note: This field is supported in OpenAPI 3.2.0+ only.
+ ///
+ public Uri? OAuth2MetadataUrl { get; }
+
///
/// Specifies that a security scheme is deprecated and SHOULD be transitioned out of usage.
/// Note: This field is supported in OpenAPI 3.2.0+. For earlier versions, it will be serialized as x-oai-deprecated extension.
diff --git a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs
index b87c9079d..543baae29 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiConstants.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiConstants.cs
@@ -695,6 +695,11 @@ public static class OpenApiConstants
///
public const string Flows = "flows";
+ ///
+ /// Field: Oauth2MetadataUrl
+ ///
+ public const string OAuth2MetadataUrl = "oauth2MetadataUrl";
+
///
/// Field: OpenIdConnectUrl
///
diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
index 57603e0aa..6278096b2 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
@@ -35,6 +35,9 @@ public class OpenApiSecurityScheme : IOpenApiExtensible, IOpenApiSecurityScheme
///
public Uri? OpenIdConnectUrl { get; set; }
+ ///
+ public Uri? OAuth2MetadataUrl { get; set; }
+
///
public bool Deprecated { get; set; }
@@ -60,6 +63,7 @@ internal OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme)
BearerFormat = securityScheme.BearerFormat ?? BearerFormat;
Flows = securityScheme.Flows != null ? new(securityScheme.Flows) : null;
OpenIdConnectUrl = securityScheme.OpenIdConnectUrl != null ? new Uri(securityScheme.OpenIdConnectUrl.OriginalString, UriKind.RelativeOrAbsolute) : null;
+ OAuth2MetadataUrl = securityScheme.OAuth2MetadataUrl != null ? new Uri(securityScheme.OAuth2MetadataUrl.OriginalString, UriKind.RelativeOrAbsolute) : null;
Deprecated = securityScheme.Deprecated;
Extensions = securityScheme.Extensions != null ? new Dictionary(securityScheme.Extensions) : null;
}
@@ -118,7 +122,12 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
break;
case SecuritySchemeType.OAuth2:
// This property apply to oauth2 type only.
+ // oauth2MetadataUrl
// flows
+ if (version >= OpenApiSpecVersion.OpenApi3_2)
+ {
+ writer.WriteProperty(OpenApiConstants.OAuth2MetadataUrl, OAuth2MetadataUrl?.ToString());
+ }
writer.WriteOptionalObject(OpenApiConstants.Flows, Flows, callback);
break;
case SecuritySchemeType.OpenIdConnect:
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
index 4267315e3..25ed6e25f 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
@@ -54,6 +54,9 @@ public string? Description
///
public Uri? OpenIdConnectUrl { get => Target?.OpenIdConnectUrl; }
+ ///
+ public Uri? OAuth2MetadataUrl { get => Target?.OAuth2MetadataUrl; }
+
///
public IDictionary? Extensions { get => Target?.Extensions; }
diff --git a/src/Microsoft.OpenApi/Reader/V32/OpenApiSecuritySchemeDeserializer.cs b/src/Microsoft.OpenApi/Reader/V32/OpenApiSecuritySchemeDeserializer.cs
index 34e3f589e..f0acc7ea6 100644
--- a/src/Microsoft.OpenApi/Reader/V32/OpenApiSecuritySchemeDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V32/OpenApiSecuritySchemeDeserializer.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
@@ -68,6 +68,16 @@ internal static partial class OpenApiV32Deserializer
}
}
},
+ {
+ "oauth2MetadataUrl", (o, n, _) =>
+ {
+ var metadataUrl = n.GetScalarValue();
+ if (metadataUrl != null)
+ {
+ o.OAuth2MetadataUrl = new(metadataUrl, UriKind.RelativeOrAbsolute);
+ }
+ }
+ },
{
"flows", (o, n, t) =>
{
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V32Tests/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V32Tests/OpenApiSecuritySchemeTests.cs
index ea0937237..50c836f66 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V32Tests/OpenApiSecuritySchemeTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V32Tests/OpenApiSecuritySchemeTests.cs
@@ -86,6 +86,36 @@ public async Task ParseOAuth2SecuritySchemeShouldSucceed()
}, securityScheme);
}
+ [Fact]
+ public async Task ParseOAuth2SecuritySchemeWithMetadataUrlShouldSucceed()
+ {
+ // Act
+ var securityScheme = await OpenApiModelFactory.LoadAsync(
+ Path.Combine(SampleFolderPath, "oauth2SecuritySchemeWithMetadataUrl.yaml"),
+ OpenApiSpecVersion.OpenApi3_2,
+ new(),
+ SettingsFixture.ReaderSettings);
+
+ // Assert
+ Assert.Equivalent(
+ new OpenApiSecurityScheme
+ {
+ Type = SecuritySchemeType.OAuth2,
+ OAuth2MetadataUrl = new Uri("https://idp.example.com/.well-known/oauth-authorization-server"),
+ Flows = new OpenApiOAuthFlows
+ {
+ ClientCredentials = new OpenApiOAuthFlow
+ {
+ TokenUrl = new Uri("https://idp.example.com/oauth/token"),
+ Scopes = new System.Collections.Generic.Dictionary
+ {
+ ["scope:one"] = "Scope one"
+ }
+ }
+ }
+ }, securityScheme);
+ }
+
[Fact]
public async Task ParseOpenIdConnectSecuritySchemeShouldSucceed()
{
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/oauth2SecuritySchemeWithMetadataUrl.yaml b/test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/oauth2SecuritySchemeWithMetadataUrl.yaml
new file mode 100644
index 000000000..612f65fde
--- /dev/null
+++ b/test/Microsoft.OpenApi.Readers.Tests/V32Tests/Samples/OpenApiSecurityScheme/oauth2SecuritySchemeWithMetadataUrl.yaml
@@ -0,0 +1,8 @@
+# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.2.0.md#securitySchemeObject
+type: oauth2
+oauth2MetadataUrl: https://idp.example.com/.well-known/oauth-authorization-server
+flows:
+ clientCredentials:
+ tokenUrl: https://idp.example.com/oauth/token
+ scopes:
+ scope:one: Scope one
diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs
index cd8499b9f..6a234c99f 100644
--- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs
@@ -93,6 +93,24 @@ public class OpenApiSecuritySchemeTests
}
};
+ private static OpenApiSecurityScheme OAuth2MetadataSecurityScheme => new()
+ {
+ Description = "description1",
+ Type = SecuritySchemeType.OAuth2,
+ OAuth2MetadataUrl = new("https://idp.example.com/.well-known/oauth-authorization-server"),
+ Flows = new()
+ {
+ ClientCredentials = new()
+ {
+ TokenUrl = new("https://idp.example.com/oauth/token"),
+ Scopes = new Dictionary
+ {
+ ["scope:one"] = "Scope one"
+ }
+ }
+ }
+ };
+
private static OpenApiSecurityScheme OpenIdConnectSecurityScheme => new()
{
Description = "description1",
@@ -257,6 +275,61 @@ public async Task SerializeOAuthSingleFlowSecuritySchemeAsV3JsonWorks()
Assert.Equal(expected, actual);
}
+ [Fact]
+ public async Task SerializeOAuthSecuritySchemeWithMetadataUrlAsV32JsonWorks()
+ {
+ // Arrange
+ var expected =
+ """
+ {
+ "type": "oauth2",
+ "description": "description1",
+ "oauth2MetadataUrl": "https://idp.example.com/.well-known/oauth-authorization-server",
+ "flows": {
+ "clientCredentials": {
+ "tokenUrl": "https://idp.example.com/oauth/token",
+ "scopes": {
+ "scope:one": "Scope one"
+ }
+ }
+ }
+ }
+ """;
+
+ // Act
+ var actual = await OAuth2MetadataSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_2);
+
+ // Assert
+ Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
+ }
+
+ [Fact]
+ public async Task SerializeOAuthSecuritySchemeWithMetadataUrlAsV31JsonOmitsMetadataUrl()
+ {
+ // Arrange
+ var expected =
+ """
+ {
+ "type": "oauth2",
+ "description": "description1",
+ "flows": {
+ "clientCredentials": {
+ "tokenUrl": "https://idp.example.com/oauth/token",
+ "scopes": {
+ "scope:one": "Scope one"
+ }
+ }
+ }
+ }
+ """;
+
+ // Act
+ var actual = await OAuth2MetadataSecurityScheme.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_1);
+
+ // Assert
+ Assert.True(JsonNode.DeepEquals(JsonNode.Parse(expected), JsonNode.Parse(actual)));
+ }
+
[Fact]
public async Task SerializeOAuthMultipleFlowSecuritySchemeAsV3JsonWorks()
{
From 14b73bf3288eb56a12eb53e401422561b01f87d4 Mon Sep 17 00:00:00 2001
From: mdaneri
Date: Thu, 22 Jan 2026 11:25:14 -0800
Subject: [PATCH 2/8] Add x-oauth2-metadata-url serialization for OAuth2
schemes
When serializing OAuth2 security schemes, the OAuth2MetadataUrl is now written as 'x-oauth2-metadata-url' for OpenAPI 3.1 and later. Updated tests and public API documentation to reflect this change.
---
src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs | 4 ++++
.../Models/OpenApiSecuritySchemeTests.cs | 1 +
test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt | 4 ++++
3 files changed, 9 insertions(+)
diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
index 6278096b2..b1670de6d 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
@@ -128,6 +128,10 @@ private void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version
{
writer.WriteProperty(OpenApiConstants.OAuth2MetadataUrl, OAuth2MetadataUrl?.ToString());
}
+ else
+ {
+ writer.WriteProperty("x-oauth2-metadata-url", OAuth2MetadataUrl?.ToString());
+ }
writer.WriteOptionalObject(OpenApiConstants.Flows, Flows, callback);
break;
case SecuritySchemeType.OpenIdConnect:
diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs
index 6a234c99f..b826c89b3 100644
--- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs
+++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSecuritySchemeTests.cs
@@ -312,6 +312,7 @@ public async Task SerializeOAuthSecuritySchemeWithMetadataUrlAsV31JsonOmitsMetad
{
"type": "oauth2",
"description": "description1",
+ "x-oauth2-metadata-url": "https://idp.example.com/.well-known/oauth-authorization-server",
"flows": {
"clientCredentials": {
"tokenUrl": "https://idp.example.com/oauth/token",
diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
index 5413879c0..b1c9810e5 100644
--- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
+++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
@@ -288,6 +288,7 @@ namespace Microsoft.OpenApi
Microsoft.OpenApi.OpenApiOAuthFlows? Flows { get; }
Microsoft.OpenApi.ParameterLocation? In { get; }
string? Name { get; }
+ System.Uri? OAuth2MetadataUrl { get; }
System.Uri? OpenIdConnectUrl { get; }
string? Scheme { get; }
Microsoft.OpenApi.SecuritySchemeType? Type { get; }
@@ -538,6 +539,7 @@ namespace Microsoft.OpenApi
public const string Null = "null";
public const string Nullable = "nullable";
public const string NullableExtension = "x-nullable";
+ public const string OAuth2MetadataUrl = "oauth2MetadataUrl";
public const string OneOf = "oneOf";
public const string OpenApi = "openapi";
public const string OpenIdConnectUrl = "openIdConnectUrl";
@@ -1381,6 +1383,7 @@ namespace Microsoft.OpenApi
public Microsoft.OpenApi.OpenApiOAuthFlows? Flows { get; set; }
public Microsoft.OpenApi.ParameterLocation? In { get; set; }
public string? Name { get; set; }
+ public System.Uri? OAuth2MetadataUrl { get; set; }
public System.Uri? OpenIdConnectUrl { get; set; }
public string? Scheme { get; set; }
public Microsoft.OpenApi.SecuritySchemeType? Type { get; set; }
@@ -1400,6 +1403,7 @@ namespace Microsoft.OpenApi
public Microsoft.OpenApi.OpenApiOAuthFlows? Flows { get; }
public Microsoft.OpenApi.ParameterLocation? In { get; }
public string? Name { get; }
+ public System.Uri? OAuth2MetadataUrl { get; }
public System.Uri? OpenIdConnectUrl { get; }
public string? Scheme { get; }
public Microsoft.OpenApi.SecuritySchemeType? Type { get; }
From 33a968bbeda431fb05bd12d1e246944d877245a0 Mon Sep 17 00:00:00 2001
From: mdaneri
Date: Wed, 18 Feb 2026 19:46:46 +0000
Subject: [PATCH 3/8] feat(securityscheme): introduce IOAuth2MetadataProvider
for OAuth2 metadata URL support
---
.../Interfaces/IOAuth2MetadataProvider.cs | 17 +++++++++++++++++
.../Models/Interfaces/IOpenApiSecurityScheme.cs | 15 +++++++++------
.../Models/OpenApiSecurityScheme.cs | 6 ++++--
.../OpenApiSecuritySchemeReference.cs | 4 ++--
.../PublicApi/PublicApi.approved.txt | 9 ++++++---
5 files changed, 38 insertions(+), 13 deletions(-)
create mode 100644 src/Microsoft.OpenApi/Models/Interfaces/IOAuth2MetadataProvider.cs
diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOAuth2MetadataProvider.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOAuth2MetadataProvider.cs
new file mode 100644
index 000000000..620b11010
--- /dev/null
+++ b/src/Microsoft.OpenApi/Models/Interfaces/IOAuth2MetadataProvider.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Microsoft.OpenApi;
+
+///
+/// TEMPORARY compatibility interface for accessing OAuth2 metadata URL support introduced for OpenAPI 3.2.
+/// This exists to avoid adding new members to in a minor release, which is binary breaking for existing compiled consumers.
+///
+// TODO: Remove this temporary interface and collapse this member into IOpenApiSecurityScheme in the next major version.
+public interface IOAuth2MetadataProvider
+{
+ ///
+ /// URL to the OAuth2 Authorization Server Metadata document (RFC 8414).
+ /// Note: This field is supported in OpenAPI 3.2.0+ only.
+ ///
+ public Uri? OAuth2MetadataUrl { get; }
+}
diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs
index 16da4a881..bde3d2c25 100644
--- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs
+++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSecurityScheme.cs
@@ -5,6 +5,15 @@ namespace Microsoft.OpenApi;
///
/// Defines the base properties for the security scheme object.
/// This interface is provided for type assertions but should not be implemented by package consumers beyond automatic mocking.
+///
+/// To preserve binary compatibility in minor releases, properties introduced after this interface shipped may be exposed through temporary companion interfaces.
+/// For OAuth2 metadata URL support, cast to :
+///
+/// if (securityScheme is IOAuth2MetadataProvider provider)
+/// {
+/// var oauth2MetadataUrl = provider.OAuth2MetadataUrl;
+/// }
+///
///
public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiReadOnlyExtensible, IShallowCopyable, IOpenApiReferenceable
{
@@ -46,12 +55,6 @@ public interface IOpenApiSecurityScheme : IOpenApiDescribedElement, IOpenApiRead
///
public Uri? OpenIdConnectUrl { get; }
- ///
- /// URL to the OAuth2 Authorization Server Metadata document (RFC 8414).
- /// Note: This field is supported in OpenAPI 3.2.0+ only.
- ///
- public Uri? OAuth2MetadataUrl { get; }
-
///
/// Specifies that a security scheme is deprecated and SHOULD be transitioned out of usage.
/// Note: This field is supported in OpenAPI 3.2.0+. For earlier versions, it will be serialized as x-oai-deprecated extension.
diff --git a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
index b1670de6d..626f7f2bd 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSecurityScheme.cs
@@ -9,7 +9,7 @@ namespace Microsoft.OpenApi
///
/// Security Scheme Object.
///
- public class OpenApiSecurityScheme : IOpenApiExtensible, IOpenApiSecurityScheme
+ public class OpenApiSecurityScheme : IOpenApiExtensible, IOpenApiSecurityScheme, IOAuth2MetadataProvider
{
///
public SecuritySchemeType? Type { get; set; }
@@ -63,7 +63,9 @@ internal OpenApiSecurityScheme(IOpenApiSecurityScheme securityScheme)
BearerFormat = securityScheme.BearerFormat ?? BearerFormat;
Flows = securityScheme.Flows != null ? new(securityScheme.Flows) : null;
OpenIdConnectUrl = securityScheme.OpenIdConnectUrl != null ? new Uri(securityScheme.OpenIdConnectUrl.OriginalString, UriKind.RelativeOrAbsolute) : null;
- OAuth2MetadataUrl = securityScheme.OAuth2MetadataUrl != null ? new Uri(securityScheme.OAuth2MetadataUrl.OriginalString, UriKind.RelativeOrAbsolute) : null;
+ OAuth2MetadataUrl = securityScheme is IOAuth2MetadataProvider oauth2MetadataProvider && oauth2MetadataProvider.OAuth2MetadataUrl != null
+ ? new Uri(oauth2MetadataProvider.OAuth2MetadataUrl.OriginalString, UriKind.RelativeOrAbsolute)
+ : null;
Deprecated = securityScheme.Deprecated;
Extensions = securityScheme.Extensions != null ? new Dictionary(securityScheme.Extensions) : null;
}
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
index 25ed6e25f..8fdd0b73a 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiSecuritySchemeReference.cs
@@ -9,7 +9,7 @@ namespace Microsoft.OpenApi
///
/// Security Scheme Object Reference.
///
- public class OpenApiSecuritySchemeReference : BaseOpenApiReferenceHolder, IOpenApiSecurityScheme
+ public class OpenApiSecuritySchemeReference : BaseOpenApiReferenceHolder, IOpenApiSecurityScheme, IOAuth2MetadataProvider
{
///
/// Constructor initializing the reference object.
@@ -55,7 +55,7 @@ public string? Description
public Uri? OpenIdConnectUrl { get => Target?.OpenIdConnectUrl; }
///
- public Uri? OAuth2MetadataUrl { get => Target?.OAuth2MetadataUrl; }
+ public Uri? OAuth2MetadataUrl { get => Target is IOAuth2MetadataProvider oauth2MetadataProvider ? oauth2MetadataProvider.OAuth2MetadataUrl : null; }
///
public IDictionary? Extensions { get => Target?.Extensions; }
diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
index b1c9810e5..72e17db13 100644
--- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
+++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
@@ -105,6 +105,10 @@ namespace Microsoft.OpenApi
{
System.Collections.Generic.IDictionary? Metadata { get; set; }
}
+ public interface IOAuth2MetadataProvider
+ {
+ System.Uri? OAuth2MetadataUrl { get; }
+ }
public interface IOpenApiCallback : Microsoft.OpenApi.IOpenApiElement, Microsoft.OpenApi.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.IOpenApiReferenceable, Microsoft.OpenApi.IOpenApiSerializable, Microsoft.OpenApi.IShallowCopyable
{
System.Collections.Generic.Dictionary? PathItems { get; }
@@ -288,7 +292,6 @@ namespace Microsoft.OpenApi
Microsoft.OpenApi.OpenApiOAuthFlows? Flows { get; }
Microsoft.OpenApi.ParameterLocation? In { get; }
string? Name { get; }
- System.Uri? OAuth2MetadataUrl { get; }
System.Uri? OpenIdConnectUrl { get; }
string? Scheme { get; }
Microsoft.OpenApi.SecuritySchemeType? Type { get; }
@@ -1373,7 +1376,7 @@ namespace Microsoft.OpenApi
public virtual void SerializeAsV31(Microsoft.OpenApi.IOpenApiWriter writer) { }
public virtual void SerializeAsV32(Microsoft.OpenApi.IOpenApiWriter writer) { }
}
- public class OpenApiSecurityScheme : Microsoft.OpenApi.IOpenApiDescribedElement, Microsoft.OpenApi.IOpenApiElement, Microsoft.OpenApi.IOpenApiExtensible, Microsoft.OpenApi.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.IOpenApiReferenceable, Microsoft.OpenApi.IOpenApiSecurityScheme, Microsoft.OpenApi.IOpenApiSerializable, Microsoft.OpenApi.IShallowCopyable
+ public class OpenApiSecurityScheme : Microsoft.OpenApi.IOAuth2MetadataProvider, Microsoft.OpenApi.IOpenApiDescribedElement, Microsoft.OpenApi.IOpenApiElement, Microsoft.OpenApi.IOpenApiExtensible, Microsoft.OpenApi.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.IOpenApiReferenceable, Microsoft.OpenApi.IOpenApiSecurityScheme, Microsoft.OpenApi.IOpenApiSerializable, Microsoft.OpenApi.IShallowCopyable
{
public OpenApiSecurityScheme() { }
public string? BearerFormat { get; set; }
@@ -1393,7 +1396,7 @@ namespace Microsoft.OpenApi
public virtual void SerializeAsV31(Microsoft.OpenApi.IOpenApiWriter writer) { }
public virtual void SerializeAsV32(Microsoft.OpenApi.IOpenApiWriter writer) { }
}
- public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.BaseOpenApiReferenceHolder, Microsoft.OpenApi.IOpenApiDescribedElement, Microsoft.OpenApi.IOpenApiElement, Microsoft.OpenApi.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.IOpenApiReferenceable, Microsoft.OpenApi.IOpenApiSecurityScheme, Microsoft.OpenApi.IOpenApiSerializable, Microsoft.OpenApi.IShallowCopyable
+ public class OpenApiSecuritySchemeReference : Microsoft.OpenApi.BaseOpenApiReferenceHolder, Microsoft.OpenApi.IOAuth2MetadataProvider, Microsoft.OpenApi.IOpenApiDescribedElement, Microsoft.OpenApi.IOpenApiElement, Microsoft.OpenApi.IOpenApiReadOnlyExtensible, Microsoft.OpenApi.IOpenApiReferenceable, Microsoft.OpenApi.IOpenApiSecurityScheme, Microsoft.OpenApi.IOpenApiSerializable, Microsoft.OpenApi.IShallowCopyable
{
public OpenApiSecuritySchemeReference(string referenceId, Microsoft.OpenApi.OpenApiDocument? hostDocument = null, string? externalResource = null) { }
public string? BearerFormat { get; }
From c8f29c78857521488e1e2b6d2c5affce2f5233a9 Mon Sep 17 00:00:00 2001
From: mdaneri
Date: Wed, 18 Feb 2026 19:59:49 +0000
Subject: [PATCH 4/8] modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.json
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.EmptyModels-report-github.md
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.EmptyModels-report.csv
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.EmptyModels-report.html
modified:
performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.EmptyModels-report.json
---
.../performance.Descriptions-report-github.md | 22 +++---
.../performance.Descriptions-report.csv | 8 +--
.../performance.Descriptions-report.html | 22 +++---
.../performance.Descriptions-report.json | 2 +-
.../performance.EmptyModels-report-github.md | 70 +++++++++----------
.../performance.EmptyModels-report.csv | 58 +++++++--------
.../performance.EmptyModels-report.html | 70 +++++++++----------
.../performance.EmptyModels-report.json | 2 +-
8 files changed, 127 insertions(+), 127 deletions(-)
diff --git a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
index 993b5da5e..df81db3dd 100644
--- a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
+++ b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report-github.md
@@ -1,18 +1,18 @@
```
-BenchmarkDotNet v0.15.4, Windows 11 (10.0.26200.6899)
-11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores
-.NET SDK 8.0.415
- [Host] : .NET 8.0.21 (8.0.21, 8.0.2125.47513), X64 RyuJIT x86-64-v4
- ShortRun : .NET 8.0.21 (8.0.21, 8.0.2125.47513), X64 RyuJIT x86-64-v4
+BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.3 LTS (Noble Numbat) (container)
+Intel Xeon Platinum 8370C CPU 2.80GHz (Max: 3.39GHz), 1 CPU, 2 logical cores and 1 physical core
+.NET SDK 8.0.418
+ [Host] : .NET 8.0.24 (8.0.24, 8.0.2426.7010), X64 RyuJIT x86-64-v4
+ ShortRun : .NET 8.0.24 (8.0.24, 8.0.2426.7010), X64 RyuJIT x86-64-v4
Job=ShortRun IterationCount=3 LaunchCount=1
WarmupCount=3
```
-| Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
-|------------- |---------------:|---------------:|--------------:|-----------:|-----------:|----------:|-------------:|
-| PetStoreYaml | 913.5 μs | 3,348.1 μs | 183.52 μs | 58.5938 | 11.7188 | - | 361.25 KB |
-| PetStoreJson | 425.1 μs | 327.5 μs | 17.95 μs | 35.1563 | 5.8594 | - | 223.39 KB |
-| GHESYaml | 1,765,825.8 μs | 5,036,336.6 μs | 276,058.60 μs | 60000.0000 | 23000.0000 | 4000.0000 | 345082.98 KB |
-| GHESJson | 848,197.4 μs | 1,381,723.6 μs | 75,736.93 μs | 33000.0000 | 12000.0000 | 2000.0000 | 206597.63 KB |
+| Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
+|------------- |---------------:|-------------:|-------------:|-----------:|-----------:|----------:|-------------:|
+| PetStoreYaml | 594.9 μs | 1,121.5 μs | 61.47 μs | 11.7188 | - | - | 361.24 KB |
+| PetStoreJson | 329.4 μs | 1,905.6 μs | 104.45 μs | 7.8125 | 1.9531 | - | 223.1 KB |
+| GHESYaml | 1,164,634.7 μs | 868,047.1 μs | 47,580.59 μs | 17000.0000 | 14000.0000 | 3000.0000 | 345072.18 KB |
+| GHESJson | 462,077.5 μs | 294,835.8 μs | 16,160.94 μs | 8000.0000 | 6000.0000 | 1000.0000 | 206591.14 KB |
diff --git a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
index ec3b99fae..b8859ee5e 100644
--- a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
+++ b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.csv
@@ -1,5 +1,5 @@
Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Gen0,Gen1,Gen2,Allocated
-PetStoreYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,913.5 μs,"3,348.1 μs",183.52 μs,58.5938,11.7188,0.0000,361.25 KB
-PetStoreJson,ShortRun,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,425.1 μs,327.5 μs,17.95 μs,35.1563,5.8594,0.0000,223.39 KB
-GHESYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"1,765,825.8 μs","5,036,336.6 μs","276,058.60 μs",60000.0000,23000.0000,4000.0000,345082.98 KB
-GHESJson,ShortRun,False,Default,Default,Default,Default,Default,Default,11111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"848,197.4 μs","1,381,723.6 μs","75,736.93 μs",33000.0000,12000.0000,2000.0000,206597.63 KB
+PetStoreYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,11,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,594.9 μs,"1,121.5 μs",61.47 μs,11.7188,0.0000,0.0000,361.24 KB
+PetStoreJson,ShortRun,False,Default,Default,Default,Default,Default,Default,11,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,329.4 μs,"1,905.6 μs",104.45 μs,7.8125,1.9531,0.0000,223.1 KB
+GHESYaml,ShortRun,False,Default,Default,Default,Default,Default,Default,11,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"1,164,634.7 μs","868,047.1 μs","47,580.59 μs",17000.0000,14000.0000,3000.0000,345072.18 KB
+GHESJson,ShortRun,False,Default,Default,Default,Default,Default,Default,11,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 8.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"462,077.5 μs","294,835.8 μs","16,160.94 μs",8000.0000,6000.0000,1000.0000,206591.14 KB
diff --git a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
index feb037f9f..0aaf8a991 100644
--- a/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
+++ b/performance/benchmark/BenchmarkDotNet.Artifacts/results/performance.Descriptions-report.html
@@ -2,7 +2,7 @@
-performance.Descriptions-20251024-100447
+performance.Descriptions-20260218-195224