Skip to content

ASP.NET Core

Tayra integrates with ASP.NET Core through response scrubbing middleware that automatically removes or redacts [PersonalData] fields from JSON responses. This prevents personal data from being inadvertently exposed through API endpoints, log aggregators, or downstream consumers that should not have access to raw PII.

Install

shell
dotnet add package Tayra.AspNetCore
powershell
Install-Package Tayra.AspNetCore

Setup

Register Tayra core services, a key store, and the ASP.NET Core scrubbing middleware:

cs
var builder = WebApplication.CreateBuilder(args);

// Register Tayra core services and key store
builder.Services.AddTayra(opts => opts.LicenseKey = licenseKey);

// Register Tayra ASP.NET Core response scrubbing
builder.Services.AddTayraAspNetCore();

var app = builder.Build();

// Add the response scrubbing middleware to the pipeline
app.UseTayraResponseScrubbing();
anchor

The setup consists of three calls:

  1. AddTayraAspNetCore() registers TayraScrubbingOptions and related services
  2. UseTayraResponseScrubbing() adds the TayraResponseScrubbingMiddleware to the pipeline
  3. Tayra core services (AddTayra()) and a key store provide the metadata cache used to identify PII fields

Middleware Order

Call UseTayraResponseScrubbing() before any response compression middleware but after routing and authentication. The middleware needs access to endpoint metadata to check for [ScrubPersonalData] attributes.

Options

cs
// TayraScrubbingOptions — controls PII scrubbing behavior
//
// Property        Type              Default              Description
// ──────────────  ────────────────  ───────────────────  ─────────────────────────────────────
// GloballyEnabled bool              false                Scrub all endpoints (not just attributed ones)
// Mode            ScrubbingMode     Redact               Redact or Remove PII fields
// RedactedValue   string            "[REDACTED]"         Replacement text for redacted fields
// ContentTypes    HashSet<string>   {"application/json"} Content types to scrub
builder.Services.AddTayraAspNetCore(opts =>
{
    opts.GloballyEnabled = false;          // Only scrub endpoints with [ScrubPersonalData]
    opts.Mode = ScrubbingMode.Redact;      // Replace PII values with RedactedValue
    opts.RedactedValue = "[REDACTED]";     // The replacement string
    opts.ContentTypes = ["application/json"]; // Only scrub JSON responses
});
anchor
PropertyTypeDefaultDescription
GloballyEnabledboolfalseScrub all endpoints (not just attributed ones)
ModeScrubbingModeRedactRedact replaces PII values; Remove deletes the JSON property entirely
RedactedValuestring"[REDACTED]"The replacement text used in Redact mode
ContentTypesHashSet<string>{"application/json"}Only responses with matching Content-Type headers are processed

Scrubbing Modes

  • ScrubbingMode.Redact -- Replaces PII field values with the RedactedValue string. The JSON structure is preserved, and consumers can see which fields exist but not their values.
  • ScrubbingMode.Remove -- Removes PII fields entirely from the JSON response. Consumers will not see the fields at all.

The ScrubPersonalData Attribute

Use [ScrubPersonalData] to opt individual endpoints or controllers into response scrubbing:

cs
// The [ScrubPersonalData] attribute marks endpoints for response scrubbing.
// Apply it to controller classes or individual action methods.
//
// [ApiController]
// [Route("api/[controller]")]
// public class CustomersController : ControllerBase
// {
//     [HttpGet("{id}")]
//     [ScrubPersonalData]  // <-- PII fields will be scrubbed from the JSON response
//     public async Task<CustomerResponse> Get(string id) { ... }
// }
anchor

The attribute can be applied to:

  • Controller classes -- All actions in the controller are scrubbed
  • Action methods -- Only the specific action is scrubbed
  • Minimal API delegates -- Applied inline on the lambda

When GloballyEnabled is false (the default), only endpoints decorated with [ScrubPersonalData] are scrubbed. When GloballyEnabled is true, all endpoints are scrubbed regardless of the attribute.

Example Endpoints

cs
// Example using Minimal APIs with the [ScrubPersonalData] attribute.
// PII fields in the response are replaced with "[REDACTED]" by the middleware.

app.MapGet("/api/customers/{id}", [ScrubPersonalData] (string id) =>
{
    return new CustomerResponse
    {
        CustomerId = id,
        Name = "Jane Doe",
        Email = "jane@example.com",
        AccountType = "Premium",
    };
});

// Without the attribute, PII fields pass through untouched
app.MapGet("/api/customers/{id}/raw", (string id) =>
{
    return new CustomerResponse
    {
        CustomerId = id,
        Name = "Jane Doe",
        Email = "jane@example.com",
        AccountType = "Premium",
    };
});
anchor

In this example:

  • GET /api/customers/42 returns the response with Name and Email replaced by "[REDACTED]" because the endpoint has [ScrubPersonalData]
  • GET /api/customers/42/raw returns the full response with plaintext PII because it lacks the attribute

Example scrubbed response:

json
{
  "customerId": "42",
  "name": "[REDACTED]",
  "email": "[REDACTED]",
  "accountType": "Premium"
}

How Response Scrubbing Works

The TayraResponseScrubbingMiddleware operates in five steps:

  1. Check eligibility -- Examines the endpoint metadata for [ScrubPersonalData] (or checks GloballyEnabled)
  2. Buffer the response -- Replaces the response body stream with a MemoryStream to capture the output
  3. Execute the pipeline -- Calls next(context) to let the rest of the pipeline write the response
  4. Parse and scrub -- If the Content-Type matches, parses the JSON response and replaces or removes fields whose names match known [PersonalData] property names
  5. Write the scrubbed response -- Writes the modified JSON back to the original response stream

Field Name Matching

The middleware uses a case-insensitive match against property names registered in the PersonalDataMetadataCache. Any type that has been seen by the Tayra metadata cache (through encryption, decryption, or explicit registration) will have its PII field names recognized for scrubbing.

Use with Encryption

Response scrubbing is complementary to field-level encryption. Encryption protects data at rest in the database, while scrubbing protects data in API responses. You can use both together for defense in depth:

  • Store encrypted PII in the database (via EF Core or Marten integration)
  • Decrypt on read for authorized endpoints
  • Scrub responses for endpoints that should not expose raw PII

See Also