Introduction
With the release of .NET 9, Microsoft no longer includes the default Swagger UI in new API projects. Instead, the built-in OpenAPI support provides JSON documentation for endpoints and schemas, and developers can choose their preferred UI layer.
This article shows how to use Scalar in a .NET API project and how to configure JWT authentication so Scalar can expose a global auth input.
Create a New Project
When you create a new .NET 9 API project and enable OpenAPI support, Visual Studio adds the OpenAPI package and registers it in Program.cs.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
When you run the API and open /OpenApi/v1.json, you will see the generated OpenAPI document.

Configure Scalar
Install the Scalar.AspNetCore package.

Then add Scalar to Program.cs.
app.MapScalarApiReference();Once that is set up, Scalar becomes available at /Scalar/V1.

Configure Scalar Options
Scalar supports several UI options, including:
- Title
- DarkMode
- Favicon
- DefaultHttpClient
- HideModels
- Layout
- ShowSidebar
Open Scalar UI by Default
You can set the launch URL in launchsettings.json so you do not need to type /Scalar/V1 every time.

Working with Authorization and JWT Token
The article adds JWT authentication to the API and protects a test endpoint.
builder.Services
.AddAuthorization()
.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = false,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("your_jwt_key")),
ValidateIssuer = false,
ValidateAudience = false
};
});
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/test1", () => "This is test 1 endpoint")
.WithName("Test1")
.RequireAuthorization();Calling the endpoint without a token returns 401 Unauthorized.
Preferred Security Scheme
The article notes that setting PreferredSecurityScheme alone does not surface a token input in the Scalar UI.
options.Authentication = new ScalarAuthenticationOptions
{
PreferredSecurityScheme = "Bearer"
};If you pass the token in request headers manually, it works, but the goal is to expose the auth control in the UI itself.

Use an OpenAPI Document Transformer
The fix is to use an OpenAPI document transformer so Scalar understands that the API supports Bearer authentication.
internal sealed class BearerSecuritySchemeTransformer : IOpenApiDocumentTransformer
{
private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
public BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider)
{
_authenticationSchemeProvider = authenticationSchemeProvider;
}
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{
var authenticationSchemes = await _authenticationSchemeProvider.GetAllSchemesAsync();
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
{
var requirements = new Dictionary<string, OpenApiSecurityScheme>
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
In = ParameterLocation.Header,
BearerFormat = "JWT"
}
};
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes = requirements;
foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
{
operation.Value.Security.Add(new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Id = "Bearer",
Type = ReferenceType.SecurityScheme
}
}] = Array.Empty<string>()
});
}
}
}
}This transformer adds a Bearer security scheme to the OpenAPI document and applies it to all operations.

The loop marks each operation as requiring a Bearer token in the OpenAPI UI.
foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
{
operation.Value.Security.Add(new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Id = "Bearer",
Type = ReferenceType.SecurityScheme
}
}] = Array.Empty<string>()
});
}This only affects the OpenAPI/Scalar UI. It does not enforce authentication by itself. To protect the API, you still need [Authorize] or RequireAuthorization().

Add the Transformer to OpenAPI
Register the transformer in AddOpenApi.
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});Now the token can be added through the Scalar UI without manually editing headers.

Conclusion
Scalar gives .NET 9 API projects a clean UI for OpenAPI documentation, and with an OpenAPI document transformer you can also expose JWT authentication in the UI.
If you want to actually enforce authentication, add [Authorize] to controllers or use RequireAuthorization() in Minimal APIs.
The original article links to the source code on GitHub: ScalarUiWithDotNet.
