Skip to content
This repository has been archived by the owner on Jun 3, 2023. It is now read-only.

Authentication

Jussi Saarivirta edited this page Jul 28, 2019 · 4 revisions

Authentication specifics

Authentication adds a little bit more configuration to the mix. HttpExtensions itself needs to be configured as described in its documentation, at startup. The Swagger Generator also needs to know the specifics of available authorization methods, and you can describe them either at startup or inside the function you use to generate and serve the Swagger JSON.

In the example solution https://github.com/Jusas/NSwagAzureFuncAppExample1 you can find the HttpExtensionsExamples project where we configure three different authentication methods into one Function App (basic auth, API key and OAuth2 with OpenIdConnect).

Another good place to peek is the tests project, NSwag.SwaggerGeneration.AzureFunctionsV2.Tests.HttpExtensionsTestApp and its Startup assembly, NSwag.SwaggerGeneration.AzureFunctionsV2.Tests.HttpExtensionsApp.Startup. They feature authentication tests, with configurations of both HttpExtensions and the Swagger Generator for all different authentication types.

The Functions themselves don't have anything special, just using the basic syntax, like:

[HttpAuthorize(Scheme.Basic)]
[SwaggerResponse(200, typeof(MyResponse))]
[SwaggerResponse(401, typeof(object))]
[FunctionName("secrets")]
public static async Task<IActionResult> GetSecrets(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "secrets")] HttpRequest req,
    ILogger log)
{
    return new OkObjectResult(new MyResponse() { Message = $"Psssht! This is a secret: two months from now, you're gonna get promoted!" });
}

Configuring the HttpExtensions is out of the scope here (see its documentation in its own wiki), but let's look at what kind of configuration is required for the Swagger Generator to output correct stuff.

In this example we're putting the configuration into a static class in the Startup project, simply to keep the Function itself clean. This covers three types of different authorization methods (quite unusual for a single API). Note: this example is for NSwag v13. The older v12 has a bit different namespaces and some classes are named differently.

So here's what we've got:

using System.Collections.Generic;
using NSwag;
using NSwag.SwaggerGeneration.AzureFunctionsV2;
using NSwag.SwaggerGeneration.AzureFunctionsV2.Processors;
using NSwag.Generation.Processors.Security;

namespace HttpExtensionsExamples.Startup
{
    public static class SwaggerConfiguration
    {
        public static AzureFunctionsV2ToSwaggerGeneratorSettings SwaggerGeneratorSettings { get; set; }

        /// <summary>
        /// Initialize SwaggerGenerator configuration.
        /// Add OperationSecurityProcessors and SecurityDefinitionAppenders to the settings.
        /// </summary>
        static SwaggerConfiguration()
        {
            var settings = new AzureFunctionsV2ToSwaggerGeneratorSettings();
            SwaggerGeneratorSettings = settings;

            // The SecurityDefinitionAppender constructor is not actually obsolete, see
            // https://github.com/RicoSuter/NSwag/pull/2305
			
            settings.OperationProcessors.Add(new OperationSecurityProcessor("Basic",
                OpenApiSecuritySchemeType.Basic));
            settings.DocumentProcessors.Add(new SecurityDefinitionAppender("Basic", new OpenApiSecurityScheme()
            {
                Type = OpenApiSecuritySchemeType.Basic,
                Scheme = "Basic",
                Description = "Basic auth"
            }));

            settings.OperationProcessors.Add(new OperationSecurityProcessor("ApiKey",
                OpenApiSecuritySchemeType.ApiKey, OpenApiSecurityApiKeyLocation.Header));
            settings.DocumentProcessors.Add(new SecurityDefinitionAppender("ApiKey", new OpenApiSecurityScheme()
            {
                Type = OpenApiSecuritySchemeType.ApiKey,
                Name = "x-apikey",
                In = OpenApiSecurityApiKeyLocation.Header
            }));

            var scopes = new List<string>() {"openid", "profile", "name"};
            settings.OperationProcessors.Add(new OperationSecurityProcessor("Bearer",
                OpenApiSecuritySchemeType.OpenIdConnect));
            settings.DocumentProcessors.Add(new SecurityDefinitionAppender("Bearer", scopes, new OpenApiSecurityScheme()
            {
                Type = OpenApiSecuritySchemeType.OAuth2,
                Flow = OpenApiOAuth2Flow.Implicit,
                AuthorizationUrl = "https://jusas-tests.eu.auth0.com/authorize",
                Scopes = scopes.ToDictionary(x => x, x => x),
                TokenUrl = "https://jusas-tests.eu.auth0.com/oauth/token",
                Description = "Token"
            }));
        }

    }
}

This is pretty much NSwag specific stuff, and not particularly specific to the Azure Functions Swagger Generator. The OperationSecurityProcessor is however a specific implementation to handle the different authentication attributes in NSwag.SwaggerGeneration.AzureFunctionsV2, and goes hand to hand with the SecurityDefinitionAppender - the processors bind the different security schemes introduced by the appenders into the specific Functions.

When your configuration is correct, Swagger UI will present you with the correct authentication options.