Search code examples
c#oauthswaggerfusionauthfast-endpoints

Swagger change UI parameters using Fastendpoints


I'm using FastEndpoints with .NET 8 and implementing an OAuth flow using FusionAuth. The integration is working fine, but I'm facing an issue with the Swagger UI when using the AuthorizationCode flow.

My issue is related to the Swagger UI's oauth2RedirectUrl parameter.

Here's a snippet of my Program.cs where I set up Swagger and configure its UI:


bld.Services.AddFastEndpoints().AddAuthorization().SwaggerDocument(options =>
{
    //Code...
    // Security scheme used on swagger:
    var securityScheme = new NSwag.OpenApiSecurityScheme
    {
        Type = NSwag.OpenApiSecuritySchemeType.OAuth2,
        Flows = new NSwag.OpenApiOAuthFlows
        {
            AuthorizationCode = new NSwag.OpenApiOAuthFlow
            {
                AuthorizationUrl = authorizationUrl,
                TokenUrl = tokenUrl,
                Scopes = new Dictionary<string, string>
                    {
                        { "offline_access", "Offline access" },
                    }
            }
        },
    };

    options.DocumentSettings = s =>
    {
        //Code...
        //Set security Scheme:
        s.AddAuth("oauth2", securityScheme);
    };
});


app.UseFastEndpoints(o =>
{
  // Code...
}).UseSwaggerGen(o => { }, uiConfig =>
{
    uiConfig.ServerUrl = fusionAuthConfig["RedirectUri"];
    uiConfig.OAuth2Client = new OAuth2ClientSettings
    {
        Realm = "",
        ClientId = fusionAuthConfig["ApplicationId"],
        ClientSecret = fusionAuthConfig["ClientSecret"],
        AppName = fusionAuthConfig["ApplicationId"],
        ScopeSeparator = ",",
        AdditionalQueryStringParameters =
                {
                    { "tenantId", fusionAuthConfig["TenantId"] },
                    { "code_challenge", "XXXXXX" },
                    { "code_challenge_method", "S256" },
                }
    };
});

Swagger UI to generate the UI ( SwaggerUiSettings : SwaggerUiSettingsBase) they have:


    internal override async Task<string> TransformHtmlAsync(string html, HttpRequest request, CancellationToken cancellationToken)
    {
        StringBuilder htmlBuilder = new StringBuilder(html);
        OAuth2ClientSettings oAuth2ClientSettings = OAuth2Client ?? new OAuth2ClientSettings();
        foreach (PropertyInfo runtimeProperty in oAuth2ClientSettings.GetType().GetRuntimeProperties())
        {
            object value = runtimeProperty.GetValue(oAuth2ClientSettings);
            if (value is ICollection value2)
            {
                htmlBuilder.Replace("{" + runtimeProperty.Name + "}", JsonConvert.SerializeObject(value2));
            }
            else if (value is bool flag)
            {
                htmlBuilder.Replace("{" + runtimeProperty.Name + "}", flag.ToString().ToLowerInvariant());
            }
            else
            {
                htmlBuilder.Replace("{" + runtimeProperty.Name + "}", value?.ToString() ?? "");
            }
        }

        ICollection<SwaggerUi3Route> collection = ((SwaggerRoutesFactory == null) ? SwaggerRoutes : (await SwaggerRoutesFactory(request, cancellationToken)).ToList());
        ICollection<SwaggerUi3Route> source = collection;
        htmlBuilder.Replace("{Urls}", (!source.Any()) ? "undefined" : JsonConvert.SerializeObject(source.Select((SwaggerUi3Route r) => new SwaggerUi3Route(r.Name, base.TransformToExternalPath(r.Url.Substring(base.MiddlewareBasePath?.Length ?? 0), request)))));
        htmlBuilder.Replace("{ValidatorUrl}", ValidateSpecification ? "undefined" : "null").Replace("{AdditionalSettings}", GenerateAdditionalSettings(AdditionalSettings)).Replace("{EnableTryItOut}", EnableTryItOut.ToString().ToLower())
            .Replace("{RedirectUrl}", string.IsNullOrEmpty(ServerUrl) ? ("window.location.origin + \"" + base.TransformToExternalPath(base.Path, request) + "/oauth2-redirect.html\"") : ("\"" + ServerUrl + base.TransformToExternalPath(base.Path, request) + "/oauth2-redirect.html\""))
            .Replace("{CustomStyle}", GetCustomStyleHtml(request))
            .Replace("{CustomScript}", GetCustomScriptHtml(request))
            .Replace("{CustomHeadContent}", CustomHeadContent)
            .Replace("{DocumentTitle}", DocumentTitle);
        return htmlBuilder.ToString();
    }

They make this:

.Replace("{RedirectUrl}", string.IsNullOrEmpty(ServerUrl) ? ("window.location.origin + \"" + base.TransformToExternalPath(base.Path, request) + "/oauth2-redirect.html\"") : ("\"" + ServerUrl + base.TransformToExternalPath(base.Path, request) + "/oauth2-redirect.html\""))

Setting redirect_url to "/oauth2-redirect.html\".

I have tried to set by my own the redirect URI sending a parameter but I was not able to figure out the way. I have already tried sending it as AdditionalQueryStringParameters = { "redirect_uri", fusionAuthConfig["RedirectUri"] } but I get 2 redirect uri's parameter. I know that in Swagger it exists a parameter called oauth2RedirectUrl (https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) but I'm not able to change it.

Does anybody knows how can I change that parameter?

Thanks.


Solution

  • After reaching out FE staff community on Discord we made a fast work around.

    Just set the parameter with: uiConfig.AdditionalSettings["oauth2RedirectUrl"] = fusionAuthConfig["RedirectUriSwagger"];

    So we have:

    .UseSwaggerGen(o => { }, uiConfig =>
    {
        uiConfig.AdditionalSettings["oauth2RedirectUrl"] = fusionAuthConfig["RedirectUriSwagger"];
        uiConfig.ServerUrl = fusionAuthConfig["RedirectUri"];
        uiConfig.OAuth2Client = new OAuth2ClientSettings
        {
            ClientId = fusionAuthConfig["ApplicationId"],
            ClientSecret = fusionAuthConfig["ClientSecret"],
            AppName = fusionAuthConfig["ApplicationId"],
            ScopeSeparator = ",",
            AdditionalQueryStringParameters =
                    {
                        { "tenantId", fusionAuthConfig["TenantId"] },
                        { "code_challenge", "CCCCCCC" },
                        { "code_challenge_method", "S256" },
                    }
        };
    });