.NET Aspire
The Scalar.Aspire
package seamlessly integrates Scalar API Reference into your .NET Aspire applications, providing a unified documentation interface for all your services.
Overview
Scalar for Aspire provides:
- Unified API Documentation: View documentation for all services in a single, cohesive interface
- Simplified Service Discovery: Automatically discover and configure API endpoints from your Aspire services
- Multiple Document Support: Each service can expose multiple OpenAPI specifications
- CORS Issue Elimination: Built-in proxy (enabled by default) handles API requests without requiring CORS configuration
- HTTPS Support: Complete support for both HTTP and HTTPS endpoints with automatic handling
Prerequisites
The Scalar Aspire integration requires a container solution such as Docker or Podman to be installed on your machine.
Service Requirements
Each service you want to include in the API Reference must:
- Expose OpenAPI documents over HTTP or HTTPS endpoints
- Implement the
IResourceWithServiceDiscovery
interface
Quick Start
1. Install the Package
dotnet add package Scalar.Aspire
2. Basic Configuration
Add the integration to your AppHost:
using Scalar.Aspire;
var builder = DistributedApplication.CreateBuilder(args);
// Add your services
var userService = builder.AddNpmApp("user-service", "../MyUserService");
var bookService = builder.AddProject<Projects.BookService>("book-service");
// Add Scalar API Reference
var scalar = builder.AddScalarApiReference();
// Register services with the API Reference
scalar
.WithApiReference(userService)
.WithApiReference(bookService);
builder.Build().Run();
That's it! 🎉 The Aspire dashboard will display a Scalar API Reference resource with unified documentation for all your services.
Configuration
Global Configuration
Configure global settings that apply to all services:
var scalar = builder.AddScalarApiReference(options =>
{
options.WithTheme(ScalarTheme.Purple);
});
Service Configuration
Register services with custom configuration options:
scalar.WithApiReference(bookService, options =>
{
options
.AddDocument("v1", "Book Management API")
.WithOpenApiRoutePattern("/api-documentation/{documentName}.json")
.WithTheme(ScalarTheme.Mars);
});
Multiple OpenAPI Documents
Services can expose multiple OpenAPI specifications:
scalar.WithApiReference(catalogService, options =>
{
// Add individual documents with custom titles
options
.AddDocument("v1", "Catalog API v1")
.AddDocument("v2", "Catalog API v2")
.AddDocument("admin", "Admin API", routePattern: "/admin/{documentName}.json");
});
// Or add multiple documents at once
scalar.WithApiReference(userService, options =>
{
options.AddDocuments("public", "internal", "admin");
});
// Set a specific document as default
scalar.WithApiReference(bookService, options =>
{
options
.AddDocument("v1", "Book API v1")
.AddDocument("v2", "Book API v2", isDefault: true)
.AddDocument("beta", "Book API Beta", "/beta/{documentName}.json");
});
HTTPS Support
Scalar supports HTTPS endpoints.
Basic HTTPS Configuration
var scalar = builder.AddScalarApiReference(options =>
{
options
.PreferHttpsEndpoint() // Use HTTPS endpoints when available
.AllowSelfSignedCertificates(); // Trust self-signed certificates
});
The AllowSelfSignedCertificates()
method should only be used in development environments, never in production.
How HTTPS Support Works
- Protocol Selection: HTTP is used by default. Use
PreferHttpsEndpoint()
to prioritize HTTPS when available - Automatic Configuration: When HTTPS is preferred, both OpenAPI document routes and server URLs are automatically configured to use HTTPS endpoints
- Automatic Redirects: HTTP to HTTPS redirects are handled automatically with proper header rewriting (localhost only)
- Certificate Validation: Self-signed certificates can be trusted in development using
AllowSelfSignedCertificates()
- Fallback Behavior: If HTTPS is preferred but unavailable, HTTP endpoints are used as fallback. Conversely, if no HTTP endpoint is available, HTTPS endpoints are automatically used
Currently, the Scalar API Reference interface is hosted over HTTP, even when communicating with HTTPS services. Support for hosting the Scalar interface under HTTPS will be added in a future release.
Proxy Configuration
Scalar for Aspire includes a built-in proxy that is enabled by default to provide seamless integration with your services.
How the Proxy Works
When the proxy is enabled:
- Eliminates CORS Issues: All API requests are routed through the Scalar proxy, avoiding CORS restrictions
- Service Discovery Integration: OpenAPI servers and document routes are configured to use service discovery endpoints through the proxy
- Default Endpoint: The proxy is served at
/scalar-proxy
Disabling the Proxy
You can disable the default proxy if you prefer direct service communication:
var scalar = builder.AddScalarApiReference(options =>
{
options.DisableDefaultProxy();
});
When the proxy is disabled:
- Direct Service Communication: OpenAPI documents and servers point directly to the actual service endpoints
- CORS Configuration Required: You'll need to configure CORS on your services to allow requests from the Scalar interface
Authentication
Configure authentication globally or per service to secure your API documentation.
Global Authentication
Apply authentication settings to all services:
var scalar = builder.AddScalarApiReference(options =>
{
options
.AddPreferredSecuritySchemes("OAuth2", "ApiKey")
.AddAuthorizationCodeFlow("OAuth2", flow =>
{
flow
.WithClientId("aspire-client")
.WithAuthorizationUrl("https://auth.example.com/oauth2/authorize")
.WithTokenUrl("https://auth.example.com/oauth2/token");
})
.AddApiKeyAuthentication("ApiKey", apiKey =>
{
apiKey.WithValue("your-development-api-key");
});
});
When the proxy is enabled, OAuth token requests are automatically proxied through the Scalar proxy to avoid CORS issues. However, interactive authorization requests are not proxied since they occur directly in the browser, so authorization URLs must be correctly configured and accessible. See the Aspire playground on GitHub.
Service-Specific Authentication
Configure different authentication for individual services:
scalar
.WithApiReference(weatherService, options =>
{
options
.AddPreferredSecuritySchemes("WeatherApiKey")
.AddApiKeyAuthentication("WeatherApiKey", apiKey =>
{
apiKey.WithValue("weather-service-key");
});
})
.WithApiReference(bookService, options =>
{
options
.AddPreferredSecuritySchemes("BookOAuth")
.AddAuthorizationCodeFlow("BookOAuth", flow =>
{
flow
.WithClientId("book-service-client")
.WithSelectedScopes("books:read", "books:write");
});
});
Asynchronous Configuration
Use async configuration when you need to fetch secrets or perform other asynchronous operations:
scalar.WithApiReference(bookService, async (options, cancellationToken) =>
{
options
.AddDocument("v1", "Book Management API")
.WithOpenApiRoutePattern("/api-documentation/{documentName}.json");
// Fetch API key from secure storage
var apiKey = await secretProvider.GetValueAsync("BOOKS_API_KEY", cancellationToken);
options
.AddPreferredSecuritySchemes("BookApiKey")
.AddApiKeyAuthentication("ApiKey", schema => schema.WithValue(apiKey));
});
Common Pitfalls
YARP Integration Issues
When using YARP (Aspire.Hosting.Yarp
), you may encounter proxy routing conflicts. Here are two solutions:
Solution 1: Configure Proxy URL for YARP Routes
Match the proxy URL to your YARP route pattern:
var scalar = builder
.AddScalarApiReference(options =>
{
options.WithProxyUrl("/api-documentation/scalar-proxy");
});
builder
.AddYarp("my-proxy")
.WithConfiguration(yarp =>
{
yarp
.AddRoute("/api-documentation/{**catch-all}", scalar)
.WithTransformPathRemovePrefix("/api-documentation");
});
Solution 2: Disable the Proxy
Alternatively, disable the proxy entirely, but you'll need to handle CORS configuration yourself:
var scalar = builder.AddScalarApiReference(options =>
{
options.DisableDefaultProxy();
});
Additional Resources
For more advanced configuration options see the .NET ASP.NET Core documentation. Many configuration options are similar between Scalar.AspNetCore
and Scalar.Aspire
integrations.