.NET ASP.NET Core

The Scalar.AspNetCore package provides a simple way to integrate the Scalar API reference into your .NET 8+ application.

Migration GuideCopied!

If you are upgrading from 2.1.x to 2.2.x, please refer to the migration guide. If you are upgrading from 1.x.x to 2.x.x, please refer to the migration guide.

Basic SetupCopied!

  1. Install the package
dotnet add package Scalar.AspNetCore
  1. Add the using directive
using Scalar.AspNetCore;
  1. Configure your application

Add the following to Program.cs based on your OpenAPI generator:

For Microsoft.AspNetCore.OpenApi:

builder.Services.AddOpenApi();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

For Swashbuckle:

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger(options =>
    {
        options.RouteTemplate = "/openapi/{documentName}.json";
    });
    app.MapScalarApiReference();
}

For NSwag:

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddOpenApiDocument();

if (app.Environment.IsDevelopment())
{
    app.UseOpenApi(options =>
    {
        options.Path = "/openapi/{documentName}.json";
    });
    app.MapScalarApiReference();
}

For FastEndpoints:

builder.Services.SwaggerDocument();

if (app.Environment.IsDevelopment())
{
    app.UseSwaggerGen(options =>
    {
        options.Path = "/openapi/{documentName}.json";
    });
    app.MapScalarApiReference();
}

You’re all set! πŸŽ‰ Visit /scalar to see the API Reference for the default OpenAPI document (v1).

If you have multiple OpenAPI documents, you can set them up with AddDocument or AddDocuments (see Multiple OpenAPI Documents). To view a specific document, go to /scalar/{documentName} (like /scalar/v1 or /scalar/v2-beta).

Configuration OptionsCopied!

The MapScalarApiReference method accepts an optional options parameter, which you can use to customize Scalar using the fluent API or object initializer syntax. This parameter can be of type Action<ScalarOptions> or Action<ScalarOptions, HttpContext>.

app.MapScalarApiReference(options =>
{
    // Fluent API
    options
        .WithTitle("Custom API")
        .WithSidebar(false);

    // Object initializer
    options.Title = "Custom API";
    options.ShowSidebar = false;
});

// Or with HttpContext
app.MapScalarApiReference((options, httpContext) =>
{
    // Fluent API
    options
        .WithTitle("Custom API")
        .WithSidebar(false);

    // Object initializer
    options.Title = "Custom API";
    options.ShowSidebar = false;
});

API Reference RouteCopied!

The Scalar API Reference is initially accessible at /scalar. You can customize this route using the endpointPrefix parameter:

app.MapScalarApiReference("/api-reference");

OpenAPI Document RouteCopied!

Scalar expects the OpenAPI document to be available at /openapi/{documentName}.json, which aligns with the default route used by the Microsoft.AspNetCore.OpenApi package. If your OpenAPI document is hosted at a different path (such as when using Swashbuckle or NSwag), you can specify the correct path or URL using the OpenApiRoutePattern property:

app.MapScalarApiReference(options =>
{
    options.WithOpenApiRoutePattern("/swagger/{documentName}.json");
    // or
    options.OpenApiRoutePattern = "/swagger/{documentName}.json";
    // Can also point to an external URL:
    options.OpenApiRoutePattern = "https://example.com/swagger/{documentName}.json";
});

Multiple OpenAPI DocumentsCopied!

Scalar allows you to configure multiple OpenAPI documents using the AddDocument or AddDocuments methods. By default, the document name v1 will be used. Each document can have its own custom route pattern for accessing the OpenAPI specification.

Add a Single Document

// Basic usage with default route pattern /openapi/{documentName}.json.
//Only document name is required
app.MapScalarApiReference(options => options.AddDocument("v1"));

// Optional title parameter
app.MapScalarApiReference(options => options.AddDocument("v1", "Production API"));

// Skip title but specify routePattern
app.MapScalarApiReference(options => options.AddDocument("v1",
  routePattern: "api-specs/{documentName}/openapi.json"));

// All parameters specified
app.MapScalarApiReference(options => options.AddDocument("v1",
  "Production API", "api-specs/v1/openapi.json"));

// Using external URL without title
app.MapScalarApiReference(options => options.AddDocument("external",
  routePattern: "https://api.example.com/v1/openapi.json"));

Add Multiple Documents

// Using AddDocument with different route patterns
app.MapScalarApiReference(options =>
{
    options
        .AddDocument("v1", "Production API", "api/{documentName}/spec.json")
        .AddDocument("v2-beta", "Beta API", "beta/openapi.json");
});

// Using AddDocuments with string array (uses default route pattern)
string[] versions = ["v1", "v2"];
app.MapScalarApiReference(options => options.AddDocuments(versions));

// Using AddDocuments with ScalarDocument objects
var documents = new[]
{
    new ScalarDocument("v1", "Production API", "api/v1/spec.json"),
    new ScalarDocument("v2-beta", "Beta API", "beta/openapi.json"),
    new ScalarDocument("v3-dev", "Development API", "dev/{documentName}.json")
};
app.MapScalarApiReference(options => options.AddDocuments(documents));

The routePattern parameter in AddDocument allows you to customize the URL path where the OpenAPI document is served. If not specified, it uses the global OpenApiRoutePattern from the options. The pattern can include the {documentName} placeholder which will be replaced with the document name.

AuthenticationCopied!

Scalar allows you to pre-configure authentication details for your API, making it easier for developers to test your endpoints. Scalar supports API Key, OAuth2, and HTTP authentication schemes.

Before you start: Your OpenAPI document must already include authentication security schemes for Scalar to work with them. Scalar can only pre-fill authentication details for schemes that are already defined in your OpenAPI specification.

The security schemes are added by your OpenAPI generator (NSwag, Swashbuckle, or Microsoft.AspNetCore.OpenApi). If you don't see authentication options in Scalar, check your OpenAPI generator's documentation to learn how to properly define security schemes.

Security Notice: Pre-filled authentication details are visible in the browser and should never be used in production environments. Only use this feature for development and testing.

API Key Authentication

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("ApiKey") // Make this the default auth method
    .AddApiKeyAuthentication("ApiKey", apiKey =>
    {
        apiKey.Value = "your-api-key-here";
    })
);

Bearer Token Authentication

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("BearerAuth")
    .AddHttpAuthentication("BearerAuth", auth =>
    {
        auth.Token = "eyJhbGciOiJ...";
    })
);

Basic Authentication

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("BasicAuth")
    .AddHttpAuthentication("BasicAuth", auth =>
    {
        auth.Username = "demo-user";
        auth.Password = "demo-password";
    })
);

OAuth2 Authentication

Scalar provides convenience methods for each OAuth2 flow type to pre-fill authentication details in the API reference interface:

Authorization Code Flow
app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddAuthorizationCodeFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-client-id";
        flow.ClientSecret = "your-client-secret";
        flow.Pkce = Pkce.Sha256; // Enable PKCE
        flow.SelectedScopes = ["read", "write"]; // Pre-select scopes
    })
);
Client Credentials Flow
app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddClientCredentialsFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-service-client-id";
        flow.ClientSecret = "your-service-client-secret";
        flow.SelectedScopes = ["read", "write"]; // Pre-select scopes
    })
);
Password Flow
app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddPasswordFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-client-id";
        flow.Username = "demo-user"; // Pre-fill username
        flow.Password = "demo-password"; // Pre-fill password
    })
);
Implicit Flow
app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddImplicitFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-spa-client-id";
        flow.SelectedScopes = ["openid", "profile"]; // Pre-select scopes
    })
);
Adding Custom OAuth Parameters

Many OAuth providers require additional parameters:

app.MapScalarApiReference(options => options
    .AddAuthorizationCodeFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-client-id";
        // Add provider-specific parameters
        flow
            .AddQueryParameter("audience", "https://api.example.com")
            .AddQueryParameter("resource", "https://graph.microsoft.com");

        // Alternatively, set query parameters using the property
        flow.AdditionalQueryParameters = new Dictionary<string, string>
        {
            ["audience"] = "https://api.example.com",
            ["resource"] = "https://graph.microsoft.com"
        };
    })
);
Multiple OAuth2 Flows

Configure multiple flows for the same OAuth2 scheme:

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddOAuth2Flows("OAuth2", flows =>
    {
        flows.AuthorizationCode = new AuthorizationCodeFlow
        {
            ClientId = "web-client-id",
            AuthorizationUrl = "https://auth.example.com/oauth2/authorize",
            TokenUrl = "https://auth.example.com/oauth2/token"
        };

        flows.ClientCredentials = new ClientCredentialsFlow
        {
            ClientId = "service-client-id",
            ClientSecret = "service-client-secret",
            TokenUrl = "https://auth.example.com/oauth2/token"
        };
    })
    .AddDefaultScopes("OAuth2", ["read", "write"]) // Apply to all flows
);
Manual OAuth2 Configuration

For complete control over the OAuth2 configuration:

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddOAuth2Authentication("OAuth2", scheme =>
    {
        scheme.Flows = new ScalarFlows
        {
            AuthorizationCode = new AuthorizationCodeFlow
            {
                ClientId = "your-client-id",
                RedirectUri = "https://your-app.com/callback"
            }
        };
        scheme.DefaultScopes = ["profile", "email"];
    })
);

Multiple Security Schemes

You can configure multiple security schemes at once:

app.MapScalarApiReference(options => options
    // Set multiple preferred schemes
    .AddPreferredSecuritySchemes("OAuth2", "ApiKey", "BasicAuth")

    // Configure OAuth2
    .AddAuthorizationCodeFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-client-id";
        flow.SelectedScopes = ["read", "write"];
    })

    // Configure API Key
    .AddApiKeyAuthentication("ApiKey", apiKey =>
    {
        apiKey.Value = "your-api-key";
    })

    // Configure HTTP Basic
    .AddHttpAuthentication("BasicAuth", auth =>
    {
        auth.Username = "demo-user";
        auth.Password = "demo-password";
    })
);

Fluent API Configuration

All authentication configuration shown above can also be configured using the fluent API syntax. Here is an example of how to set up multiple authentication schemes using the fluent API:

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2", "ApiKey")
    .AddOAuth2Authentication("OAuth2", scheme => scheme
        .WithFlows(flows => flows
            .WithAuthorizationCode(flow => flow
                .WithAuthorizationUrl("https://example.com/oauth2/authorize")
                .WithTokenUrl("https://example.com/oauth2/token")
                .WithRefreshUrl("https://example.com/oauth2/refresh")
                .WithClientId("web-client-id"))
            .WithClientCredentials(flow => flow
                .WithTokenUrl("https://example.com/oauth2/token")
                .WithClientId("service-client-id")
                .WithClientSecret("service-secret")
                .WithSelectedScopes("read", "write")))
        .WithDefaultScopes("profile", "email"))
    .AddApiKeyAuthentication("ApiKey", scheme => scheme.WithValue("my-api-key"))
);

Persisting Authentication

By default, authentication information is lost when the page is refreshed. To persist authentication data in the browser's local storage, use the WithPersistentAuthentication() method or the PersistentAuthentication property:

app.MapScalarApiReference(options => options
    .AddPreferredSecuritySchemes("OAuth2")
    .AddAuthorizationCodeFlow("OAuth2", flow =>
    {
        flow.ClientId = "your-client-id";
    })
    .WithPersistentAuthentication() // Enable persistence
);

With this configuration, users won't need to re-enter their authentication credentials after refreshing the page.

Persisting authentication information in the browser's local storage may present security risks in certain environments. Use this feature with caution based on your security requirements.

Custom HTTP ClientCopied!

Scalar allows you to set a default HTTP client for code samples. The ScalarTarget enum specifies the language, and the ScalarClient enum specifies the client type.

app.MapScalarApiReference(options =>
{
    options.WithDefaultHttpClient(ScalarTarget.CSharp, ScalarClient.HttpClient);
    // or
    options.DefaultHttpClient = new(ScalarTarget.CSharp, ScalarClient.HttpClient);
});

AssetsCopied!

Scalar uses local assets by default to render the UI. To load assets from a CDN or a different location, specify the CdnUrl property:

app.MapScalarApiReference(options =>
{
    options.WithCdnUrl("https://cdn.jsdelivr.net/npm/@scalar/api-reference");
    // or
    options.CdnUrl = "https://cdn.jsdelivr.net/npm/@scalar/api-reference";
});

Fonts are loaded from a CDN by default. To disable this, set DefaultFonts to false.

Custom JavaScript ConfigurationCopied!

Scalar allows you to extend its functionality by using a custom JavaScript configuration module. This is useful for customizing behavior that's not accessible through the C# configuration options.

To use this feature, specify the path to your JavaScript module using the JavaScriptConfiguration property:

app.MapScalarApiReference(options =>
{
    options.WithJavaScriptConfiguration("/scalar/config.js");
    // or
    options.JavaScriptConfiguration = "/scalar/config.js";
});

Create a JavaScript module in your static files directory (e.g. wwwroot/scalar/config.js) that exports a default object with your custom configuration:

// wwwroot/scalar/config.js
export default {
  // Custom slug generation for operations
  generateOperationSlug: (operation) => `custom-${operation.method.toLowerCase()}${operation.path}`,

  // Hook into document selection events
  onDocumentSelect: () => console.log('Document changed'),

  // Add any other custom configuration options supported by Scalar
  // Checkout https://github.com/scalar/scalar/blob/main/documentation/configuration.md)
}

Make sure to expose the directory that contains your JavaScript module through static file middleware using app.MapStaticAssets() or app.UseStaticFiles().

Dependency InjectionCopied!

Configuration options can also be set via dependency injection:

builder.Services.Configure<ScalarOptions>(options => options.Title = "My API");
// or
builder.Services.AddOptions<ScalarOptions>().BindConfiguration("Scalar");

Options set via the MapScalarApiReference method override those set through dependency injection.

Additional informationCopied!

The MapScalarApiReference method is implemented as a minimal API endpoint and returns an IEndpointConventionBuilder, allowing you to use minimal API features such as authorization:

app
  .MapScalarApiReference()
  .AllowAnonymous();

For all available configuration properties and their default values, check out the ScalarOptions and the ScalarOptionsExtensions.

Scalar OpenAPI ExtensionsCopied!

The Scalar.AspNetCore package includes extension methods and attributes to enhance your OpenAPI documents with additional metadata. However, to make these extensions functional, you must install one of the companion packages (Scalar.AspNetCore.Microsoft or Scalar.AspNetCore.Swashbuckle) and register the appropriate transformers or filters in your application.

Installation and ConfigurationCopied!

For Microsoft.AspNetCore.OpenApi

dotnet add package Scalar.AspNetCore.Microsoft
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// Register Microsoft OpenAPI and configure it to use Scalar transformers
builder.Services.AddOpenApi(options =>
{
    options.AddScalarTransformers(); // Required for extensions to work
});

var app = builder.Build();

app.MapOpenApi();
app.MapScalarApiReference();

For Swashbuckle

dotnet add package Scalar.AspNetCore.Swashbuckle
using Scalar.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    options.AddScalarFilters(); // Required for extensions to work
});

var app = builder.Build();

app.MapSwagger("/openapi/{documentName}.json");
app.MapScalarApiReference();

Available ExtensionsCopied!

API Stability

Indicates the stability status of an API endpoint:

  • Stability.Stable: Production-ready API
  • Stability.Experimental: API likely to change, not recommended for production
  • Stability.Deprecated: API will be removed in a future release
// Extension methods
app.MapGet("/products", GetProducts).Stable();
app.MapGet("/beta-features", GetBetaFeatures).Experimental();
app.MapGet("/legacy-endpoint", GetLegacyData).Deprecated();

// Attribute
[Stability(Stability.Experimental)]
public IActionResult CreateProduct() { }

Exclude From API Reference

Prevents an endpoint from appearing in the Scalar API Reference while keeping it in the OpenAPI document.

This only affects display in the Scalar API Reference. Endpoints remain in the OpenAPI document and are accessible via the API.

// Extension method
app.MapGet("/internal/metrics", GetMetrics).ExcludeFromApiReference();

// Attribute
[ExcludeFromApiReference]
public IActionResult GetInternalMetrics() { }

Code Samples

Adds code samples to API endpoints in various programming languages.

// Extension methods
app.MapPost("/orders", CreateOrder)
    .CodeSample("fetch('/orders', { method: 'POST' })", ScalarTarget.JavaScript, "Create Order")
    .CodeSample("curl -X POST /orders", ScalarTarget.Shell, "Create Order with cURL")

// Attribute
[CodeSample("fetch('/products').then(r => r.json())", ScalarTarget.JavaScript)]
public IActionResult GetProducts() { }

Usage ExamplesCopied!

Minimal APIs

using Scalar.AspNetCore;

// Using extension methods
app.MapGet("/products", GetProducts)
    .Stable()
    .CodeSample("fetch('/products').then(r => r.json())", ScalarTarget.JavaScript);

app.MapGet("/internal/health", GetHealth)
    .ExcludeFromApiReference();

// Using attributes with delegate handlers
app.MapPost("/orders", [Stability(Stability.Experimental)]
    (CreateOrderRequest request) => { /* Implementation */ });

Controller APIs

using Scalar.AspNetCore;

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet]
    [Stability(Stability.Stable)]
    [CodeSample("GET /api/products", ScalarTarget.Shell)]
    public IActionResult GetProducts() { }

    [HttpPost]
    [Stability(Stability.Experimental)]
    [ExcludeFromApiReference]
    public IActionResult CreateProduct() { }
}

Legacy .NET IntegrationCopied!

This guide explains how to integrate Scalar API Reference into .NET Framework and .NET Core projects using static assets.

PrerequisitesCopied!

  • An ASP.NET or ASP.NET Core application with OpenAPI/Swagger support (using Swashbuckle or NSwag)

Step 1: Enable Swagger/OpenAPI in your projectCopied!

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    // Using Swashbuckle
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    });

    // OR using NSwag
    services.AddOpenApiDocument();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Enable the endpoint for generating the OpenAPI documents
    app.UseSwagger();

    // Required for serving static scalar files
    app.UseStaticFiles();

    // Other middleware
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Step 2: Create the directory structureCopied!

Create the following folder structure:

wwwroot/ (or your static files directory)
└── scalar/
    β”œβ”€β”€ index.html
    └── scalar.config.js

Step 3: Create the HTML file for ScalarCopied!

Create index.html in the wwwroot/scalar directory with:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scalar API Reference</title>
</head>
<body>
    <div id="app"></div>

    <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
    <script src="./scalar.config.js"></script>
</body>
</html>

Step 4: Create the configuration fileCopied!

Create scalar.config.js in the same directory:

Scalar.initialize({
    selector: "#app",
    url: "/swagger/v1/swagger.json", // Adjust this URL to match your OpenAPI document path
    theme: "moon" // Other configuration
});

Step 5: Accessing your API ReferenceCopied!

After starting your application, the Scalar API Reference will be available at:

http://localhost:<port>/scalar/index.html

Using a specific Scalar version

To use a specific version instead of the latest, specify the version in your HTML:

<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference@1.28.23"></script>

TroubleshootingCopied!

  • Swagger JSON not loading: Verify the URL path to your Swagger JSON in the configuration
  • CORS issues: Ensure your API allows CORS if hosted on a different domain
  • Static files not serving: Check that app.UseStaticFiles() is present in your middleware pipeline
  • 404 errors: Confirm the directory structure and that the files are correctly named

For more configuration options, refer to the official Scalar configuration documentation.