> ## Documentation Index
> Fetch the complete documentation index at: https://auth0.generaltranslation.app/llms.txt
> Use this file to discover all available pages before exploring further.

# ASP.NET Core Web API

> Add Auth0 JWT authentication to an ASP.NET Core Web API with protected endpoints

<Callout icon="pencil" color="#FFC107" iconType="solid">
  This Quickstart is currently in **Beta**. We'd love to hear your feedback!
</Callout>

<Accordion title="AI Prompt" defaultOpen icon="microchip-ai" iconType="sharp-solid">
  **Using AI to integrate Auth0?** Add this prompt to Cursor, Windsurf, Copilot, Claude Code or your favourite AI-powered IDE to speed up development.

  ```markdown expandable theme={null}
  Integrate the Auth0 ASP.NET Core API SDK into a .NET Web API

  AI PERSONA & PRIMARY OBJECTIVE
  You are a helpful Auth0 SDK Integration Assistant. Your primary function is to execute commands to set up a development environment for Auth0 in ASP.NET Core. Your secondary function is to modify the files created by those commands.

  CRITICAL BEHAVIORAL INSTRUCTIONS
  1.  CHECK EXISTING PROJECT FIRST: Before creating a new project, check if the current directory already contains a .NET project (*.csproj file). If it does, skip project creation and work with the existing project.
  2.  EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropriate setup command. Do not show, suggest, or create any files until the setup is complete.
  3.  NO PLANNING: DO NOT propose a directory structure. DO NOT show a file tree. Your first action must be to run the appropriate command.
  4.  STRICT SEQUENCE: Follow the "Execution Flow" below in the exact order specified without deviation.

  EXECUTION FLOW

  Step 1: Check for Existing .NET Project and Prerequisites
  FIRST, verify prerequisites and check for existing .NET project:

    # Check if .NET SDK is available
    dotnet --version

  Then examine the current directory:

    # Check for existing .NET project
    if ls *.csproj 1> /dev/null 2>&1; then
      echo "Found .csproj file, checking project type..."
      ls -la *.csproj
    else
      echo "No .csproj found, will create new project"
    fi

  Based on the results:
  - If *.csproj exists and is a Web API project, proceed to Step 1b (install Auth0 SDK only)
  - If no .NET project exists, proceed to Step 1a (create new project)

  Step 1a: Create New Project and Install the SDK
  If an existing Web API project exists, simply install the SDK:
  dotnet add package Auth0.AspNetCore.Authentication.Api
  Otherwise, create a new project and install the SDK:

    dotnet new webapi -n Auth0Api && cd Auth0Api && dotnet add package Auth0.AspNetCore.Authentication.Api

  Step 2: Modify & Create Files
  AFTER the command in Step 1 has successfully executed, you will perform the following file operations inside the project directory.

  2.1: Setup Auth0 configuration in appsettings.json

  Add the Auth0 configuration section to appsettings.json:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "Auth0": {
        "Domain": "your-tenant.auth0.com",
        "Audience": "https://my-api"
      }
    }

  ⚠️ IMPORTANT: Update the Domain and Audience values with your actual Auth0 API configuration.

  2.2: Configure Program.cs with Auth0 authentication

  Replace the entire contents of Program.cs with this code:

    using Auth0.AspNetCore.Authentication.Api;
    using Microsoft.AspNetCore.Authentication.JwtBearer;

    var builder = WebApplication.CreateBuilder(args);

    builder.Services.AddAuth0ApiAuthentication(options =>
    {
        options.Domain = builder.Configuration["Auth0:Domain"];
        options.JwtBearerOptions = new JwtBearerOptions
        {
            Audience = builder.Configuration["Auth0:Audience"]
        };
    });

    builder.Services.AddAuthorization();

    var app = builder.Build();
    if (!app.Environment.IsDevelopment())
    {
        app.UseHttpsRedirection();
    }
    app.UseAuthentication();
    app.UseAuthorization();

    // Public endpoint - no authentication required
    app.MapGet("/api/public", () => 
        Results.Ok(new { Message = "This endpoint is public" }))
        .WithName("GetPublic");

    // Protected endpoint - requires authentication
    app.MapGet("/api/private", () => 
        Results.Ok(new { Message = "This endpoint requires authentication" }))
        .RequireAuthorization()
        .WithName("GetPrivate");

    app.Run();

  2.3: Run the application

    dotnet run

  The API will start on https://localhost:7190 (or similar - check console output for exact URL).

  CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS
  As an AI language model, you MUST NOT generate any of the following anti-patterns:
  1.  NEVER hardcode the Auth0 Domain or Audience directly in the code. This is a major security vulnerability.
  2.  NEVER omit the UseAuthentication() middleware. It MUST be called before UseAuthorization().
  3.  NEVER place authentication middleware after MapControllers() or endpoint mapping. Middleware order matters.
  4.  NEVER suggest manually validating JWT tokens. The SDK handles this securely.

  ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
  1.  You MUST use the Auth0.AspNetCore.Authentication.Api package.
  2.  You MUST retrieve credentials from configuration (appsettings.json).
  3.  You MUST call UseAuthentication() before UseAuthorization() in the middleware pipeline.
  4.  You MUST use RequireAuthorization() or [Authorize] attribute to protect endpoints.

  COMMON ISSUES ENCOUNTERED DURING INTEGRATION

  Issue 1: Configuration values not found
  Problem: Domain or Audience is null at runtime
  Solution: Ensure appsettings.json contains the Auth0 section with correct values

  Issue 2: Middleware order issues
  Problem: Authentication not working despite correct configuration
  Solution: Ensure UseAuthentication() comes before UseAuthorization() in Program.cs

  Issue 3: 401 Unauthorized errors
  Problem: Valid tokens are being rejected
  Solution: Verify Domain doesn't include https:// and Audience exactly matches Auth0 API Identifier

  Issue 4: HTTPS certificate errors in development
  Problem: SSL/TLS errors when running locally
  Solution: Run `dotnet dev-certs https --trust` to trust the development certificate
  ```
</Accordion>

<Note>
  **Prerequisites:** Before you begin, ensure you have the following installed:

  * **[.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)** or higher
  * Your preferred IDE (Visual Studio 2022, VS Code, or Rider)

  **.NET Version Compatibility:** This quickstart works with **.NET 8.0** and newer.
</Note>

## Get Started

This quickstart demonstrates how to add Auth0 JWT authentication to an ASP.NET Core Web API. You'll build a secure API with protected endpoints using the Auth0 ASP.NET Core API SDK.

<Steps>
  <Step title="Create a new project" stepNumber={1}>
    Create a new ASP.NET Core Web API project for this Quickstart

    ```bash theme={null}
    dotnet new webapi -n Auth0Api
    ```

    Open the project

    ```bash theme={null}
    cd Auth0Api
    ```
  </Step>

  <Step title="Install the Auth0 SDK" stepNumber={2}>
    ```bash theme={null}
    dotnet add package Auth0.AspNetCore.Authentication.Api
    ```
  </Step>

  <Step title="Setup your Auth0 API" stepNumber={3}>
    Next up, you need to create a new API on your Auth0 tenant and add the configuration to your project.

    You can choose to do this automatically by running a CLI command or do it manually via the Dashboard:

    <Tabs>
      <Tab title="CLI">
        Run the following shell command on your project's root directory to create an Auth0 API and update your `appsettings.json` file:

        <Tabs>
          <Tab title="Mac/Linux">
            ```bash theme={null}
            AUTH0_API_NAME="My ASP.NET Core API" && \
            AUTH0_API_IDENTIFIER="https://my-api" && \
            brew tap auth0/auth0-cli && \
            brew install auth0 && \
            auth0 login --no-input && \
            auth0 apis create -n "${AUTH0_API_NAME}" -i "${AUTH0_API_IDENTIFIER}" --offline-access --token-lifetime 86400 --signing-alg RS256 --json > auth0-api-details.json && \
            DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && \
            AUDIENCE=$(jq -r '.identifier' auth0-api-details.json) && \
            jq --arg domain "$DOMAIN" --arg audience "$AUDIENCE" \
              '.Auth0.Domain = $domain | .Auth0.Audience = $audience' \
              appsettings.json > appsettings.tmp.json && \
            mv appsettings.tmp.json appsettings.json && \
            rm auth0-api-details.json && \
            echo "✅ appsettings.json updated with your Auth0 API details:" && \
            cat appsettings.json
            ```
          </Tab>

          <Tab title="Windows (PowerShell)">
            ```powershell theme={null}
            $ApiName = "My ASP.NET Core API"
            $ApiIdentifier = "https://my-api"
            $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/auth0/auth0-cli/releases/latest"
            $latestVersion = $latestRelease.tag_name
            $version = $latestVersion -replace "^v"
            Invoke-WebRequest -Uri "https://github.com/auth0/auth0-cli/releases/download/${latestVersion}/auth0-cli_${version}_Windows_x86_64.zip" -OutFile ".\auth0.zip"
            Expand-Archive ".\auth0.zip" .\
            [System.Environment]::SetEnvironmentVariable('PATH', $Env:PATH + ";${pwd}")
            auth0 login --no-input
            auth0 apis create -n "$ApiName" -i "$ApiIdentifier" --offline-access --token-lifetime 86400 --signing-alg RS256 --json | Set-Content -Path auth0-api-details.json
            $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name
            $Audience = (Get-Content -Raw auth0-api-details.json | ConvertFrom-Json).identifier
            $Config = Get-Content -Raw appsettings.json | ConvertFrom-Json
            if (-not $Config.Auth0) { $Config | Add-Member -MemberType NoteProperty -Name Auth0 -Value @{} }
            $Config.Auth0.Domain = $Domain
            $Config.Auth0.Audience = $Audience
            $Config | ConvertTo-Json -Depth 10 | Set-Content appsettings.json
            Remove-Item auth0-api-details.json
            Write-Output "✅ appsettings.json updated with your Auth0 API details:"
            Get-Content appsettings.json
            ```
          </Tab>
        </Tabs>
      </Tab>

      <Tab title="Dashboard">
        Before you start, add Auth0 configuration to your `appsettings.json` file

        ```json appsettings.json theme={null}
        {
          "Logging": {
            "LogLevel": {
              "Default": "Information",
              "Microsoft.AspNetCore": "Warning"
            }
          },
          "AllowedHosts": "*",
          "Auth0": {
            "Domain": "YOUR_AUTH0_DOMAIN",
            "Audience": "YOUR_AUTH0_API_IDENTIFIER"
          }
        }
        ```

        1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → **APIs**
        2. Click **Create API**
        3. Enter your API details:
           * **Name**: My ASP.NET Core API
           * **Identifier**: `https://my-api` (this becomes your Audience)
           * **Signing Algorithm**: RS256
        4. Click **Create**
        5. Replace `YOUR_AUTH0_DOMAIN` in `appsettings.json` with your **Domain** from the Test tab (e.g., `your-tenant.auth0.com`)
        6. Replace `YOUR_AUTH0_API_IDENTIFIER` in `appsettings.json` with your **Identifier** (e.g., `https://my-api`)

        <Info>
          Your **Domain** should not include `https://` - use only the domain name (e.g., `your-tenant.auth0.com`).

          The **Audience** (API Identifier) is a unique identifier for your API and can be any valid URI. It doesn't need to be a publicly accessible URL.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configure authentication" stepNumber={4}>
    Replace the entire contents of `Program.cs` with the following code:

    ```csharp Program.cs lines theme={null}
    using Auth0.AspNetCore.Authentication.Api;
    using Microsoft.AspNetCore.Authentication.JwtBearer;

    var builder = WebApplication.CreateBuilder(args);

    builder.Services.AddAuth0ApiAuthentication(options =>
    {
        options.Domain = builder.Configuration["Auth0:Domain"];
        options.JwtBearerOptions = new JwtBearerOptions
        {
            Audience = builder.Configuration["Auth0:Audience"]
        };
    });

    builder.Services.AddAuthorization();

    var app = builder.Build();

    if (!app.Environment.IsDevelopment())
    {
        app.UseHttpsRedirection();
    }

    app.UseAuthentication();
    app.UseAuthorization();

    app.Run();
    ```
  </Step>

  <Step title="Create public and protected endpoints" stepNumber={5}>
    Add endpoints to test authentication. Add the following code in `Program.cs` before `app.Run()`:

    ```csharp Program.cs theme={null}
    // Public endpoint - no authentication required
    app.MapGet("/api/public", () => 
        Results.Ok(new { Message = "This endpoint is public" }))
        .WithName("GetPublic");

    // Protected endpoint - requires authentication
    app.MapGet("/api/private", () => 
        Results.Ok(new { Message = "This endpoint requires authentication" }))
        .RequireAuthorization()
        .WithName("GetPrivate");
    ```
  </Step>

  <Step title="Run your API" stepNumber={6}>
    ```bash theme={null}
    dotnet run
    ```

    Your API is now running on `https://localhost:7190` (or similar - check your console output for the exact URL).
  </Step>
</Steps>

<Check>
  **Checkpoint**

  You should now have a fully functional Auth0-protected API running on your [localhost](https://localhost:7190/)
</Check>

***

## Advanced Usage

<Accordion title="Calling Protected APIs">
  Test your protected endpoints with an access token.

  **1. Get an access token** from Auth0 using the Client Credentials flow:

  ```bash theme={null}
  curl --request POST \
    --url https://YOUR_DOMAIN/oauth/token \
    --header 'content-type: application/json' \
    --data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials"}'
  ```

  <Info>
    To get `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET`, create a Machine to Machine Application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications) and authorize it for your API.
  </Info>

  **2. Test the public endpoint** (should return 200 OK):

  ```bash theme={null}
  curl https://localhost:7190/api/public
  ```

  **3. Test the protected endpoint without authentication** (should return 401 Unauthorized):

  ```bash theme={null}
  curl https://localhost:7190/api/private
  ```

  **4. Call the protected endpoint with the token:**

  ```bash theme={null}
  curl https://localhost:7190/api/private \
    --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
  ```
</Accordion>

<Accordion title="Using Controller-Based Endpoints">
  For larger APIs, use controllers instead of minimal API endpoints.

  **1. Add controllers support:**

  ```csharp Program.cs theme={null}
  builder.Services.AddControllers();

  var app = builder.Build();

  if (!app.Environment.IsDevelopment())
  {
      app.UseHttpsRedirection();
  }

  app.UseAuthentication();
  app.UseAuthorization();

  app.MapControllers();

  app.Run();
  ```

  **2. Create a controller:**

  Create `Controllers/MessagesController.cs`:

  ```csharp Controllers/MessagesController.cs theme={null}
  using Microsoft.AspNetCore.Authorization;
  using Microsoft.AspNetCore.Mvc;

  namespace Auth0Api.Controllers;

  [ApiController]
  [Route("api/[controller]")]
  public class MessagesController : ControllerBase
  {
      [HttpGet]
      public IActionResult GetPublic()
      {
          return Ok(new { Message = "This endpoint is public" });
      }

      [Authorize]
      [HttpGet("private")]
      public IActionResult GetPrivate()
      {
          var userId = User.FindFirst("sub")?.Value;
          return Ok(new { Message = "This endpoint is protected", UserId = userId });
      }

      [Authorize(Policy = "read:messages")]
      [HttpGet("messages")]
      public IActionResult GetMessages()
      {
          return Ok(new { Messages = new[] { "Message 1", "Message 2" } });
      }
  }
  ```
</Accordion>

<Accordion title="Protecting Routes with Scope-Based Authorization">
  Protect endpoints based on specific scopes in the access token.

  **1. Define scopes in your Auth0 API:**

  In the [Auth0 Dashboard](https://manage.auth0.com) → APIs → Your API → Permissions, add scopes:

  * `read:messages` - Read messages
  * `write:messages` - Write messages

  **2. Configure authorization policies:**

  ```csharp Program.cs theme={null}
  builder.Services.AddAuthorization(options =>
  {
      options.AddPolicy("read:messages", policy =>
          policy.RequireClaim("scope", "read:messages"));
      
      options.AddPolicy("write:messages", policy =>
          policy.RequireClaim("scope", "write:messages"));
  });
  ```

  **3. Apply policies to endpoints:**

  ```csharp theme={null}
  app.MapGet("/api/messages", () => 
      Results.Ok(new { Messages = new[] { "Message 1", "Message 2" } }))
      .RequireAuthorization("read:messages");

  app.MapPost("/api/messages", () => 
      Results.Created("/api/messages/1", new { Id = 1, Text = "New message" }))
      .RequireAuthorization("write:messages");
  ```

  When requesting an access token, include the required scope:

  ```bash theme={null}
  curl --request POST \
    --url https://YOUR_DOMAIN/oauth/token \
    --header 'content-type: application/json' \
    --data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials","scope":"read:messages write:messages"}'
  ```
</Accordion>

<Accordion title="Using DPoP for Enhanced Security">
  DPoP (Demonstration of Proof-of-Possession) binds access tokens to cryptographic keys, preventing token theft and replay attacks.

  **Enable DPoP support:**

  ```csharp Program.cs theme={null}
  builder.Services.AddAuth0ApiAuthentication(options =>
  {
      options.Domain = builder.Configuration["Auth0:Domain"];
      options.JwtBearerOptions = new JwtBearerOptions
      {
          Audience = builder.Configuration["Auth0:Audience"]
      };
  }).WithDPoP();  // Enable DPoP with default settings
  ```

  **DPoP Modes:**

  Accept both DPoP and Bearer tokens (default):

  ```csharp theme={null}
  using Auth0.AspNetCore.Authentication.Api.DPoP;

  .WithDPoP(dpopOptions =>
  {
      dpopOptions.Mode = DPoPModes.Allowed;
  });
  ```

  Only accept DPoP tokens, reject Bearer tokens:

  ```csharp theme={null}
  using Auth0.AspNetCore.Authentication.Api.DPoP;

  .WithDPoP(dpopOptions =>
  {
      dpopOptions.Mode = DPoPModes.Required;
  });
  ```

  Configure time validation parameters:

  ```csharp theme={null}
  .WithDPoP(dpopOptions =>
  {
      dpopOptions.Mode = DPoPModes.Allowed;
      dpopOptions.IatOffset = 300;  // Allow DPoP proof up to 5 minutes old
      dpopOptions.Leeway = 30;      // 30 seconds clock skew tolerance
  });
  ```

  <Info>
    Learn more about DPoP in the [Auth0 DPoP Documentation](https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop).
  </Info>
</Accordion>

<Accordion title="Implementing Custom Authorization Policies">
  Create reusable authorization policies for complex requirements.

  **1. Create a custom requirement:**

  ```csharp Authorization/HasScopeRequirement.cs theme={null}
  using Microsoft.AspNetCore.Authorization;

  namespace Auth0Api.Authorization;

  public class HasScopeRequirement : IAuthorizationRequirement
  {
      public string Scope { get; }
      public string Issuer { get; }

      public HasScopeRequirement(string scope, string issuer)
      {
          Scope = scope;
          Issuer = issuer;
      }
  }
  ```

  **2. Create a handler:**

  ```csharp Authorization/HasScopeHandler.cs theme={null}
  using Microsoft.AspNetCore.Authorization;

  namespace Auth0Api.Authorization;

  public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
  {
      protected override Task HandleRequirementAsync(
          AuthorizationHandlerContext context,
          HasScopeRequirement requirement)
      {
          if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
          {
              return Task.CompletedTask;
          }

          var scopes = context.User
              .FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer)?
              .Value.Split(' ');

          if (scopes?.Any(s => s == requirement.Scope) == true)
          {
              context.Succeed(requirement);
          }

          return Task.CompletedTask;
      }
  }
  ```

  **3. Register and use the policy:**

  ```csharp Program.cs theme={null}
  using Auth0Api.Authorization;

  var builder = WebApplication.CreateBuilder(args);

  var domain = $"https://{builder.Configuration["Auth0:Domain"]}";

  builder.Services.AddAuth0ApiAuthentication(options =>
  {
      options.Domain = builder.Configuration["Auth0:Domain"];
      options.JwtBearerOptions = new JwtBearerOptions
      {
          Audience = builder.Configuration["Auth0:Audience"]
      };
  });

  builder.Services.AddAuthorization(options =>
  {
      options.AddPolicy("read:messages", policy =>
          policy.Requirements.Add(new HasScopeRequirement("read:messages", domain)));
  });

  builder.Services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();

  var app = builder.Build();
  // ... rest of configuration
  ```
</Accordion>

<Accordion title="Accessing User Information">
  Extract user information from the authenticated token.

  ```csharp theme={null}
  app.MapGet("/api/user-info", (HttpContext context) =>
  {
      var userId = context.User.FindFirst("sub")?.Value;
      var email = context.User.FindFirst("email")?.Value;
      var name = context.User.FindFirst("name")?.Value;
      var scopes = context.User.FindAll("scope")
          .SelectMany(c => c.Value.Split(' '))
          .Distinct();

      return Results.Ok(new
      {
          UserId = userId,
          Email = email,
          Name = name,
          Scopes = scopes
      });
  })
  .RequireAuthorization();
  ```
</Accordion>

<Accordion title="Custom Token Validation">
  Customize JWT token validation parameters for specific requirements.

  ```csharp Program.cs theme={null}
  using Microsoft.IdentityModel.Tokens;
  using System.Security.Claims;

  builder.Services.AddAuth0ApiAuthentication(options =>
  {
      options.Domain = builder.Configuration["Auth0:Domain"];
      options.JwtBearerOptions = new JwtBearerOptions
      {
          Audience = builder.Configuration["Auth0:Audience"],
          
          TokenValidationParameters = new TokenValidationParameters
          {
              ValidateIssuerSigningKey = true,
              ValidateIssuer = true,
              ValidateAudience = true,
              ValidateLifetime = true,
              ClockSkew = TimeSpan.FromMinutes(5),
              NameClaimType = ClaimTypes.NameIdentifier,
              RoleClaimType = "https://my-app.com/roles"
          },
          
          Events = new JwtBearerEvents
          {
              OnAuthenticationFailed = context =>
              {
                  Console.WriteLine($"Authentication failed: {context.Exception.Message}");
                  return Task.CompletedTask;
              },
              
              OnTokenValidated = context =>
              {
                  var userId = context.Principal?.FindFirst("sub")?.Value;
                  Console.WriteLine($"Token validated for user: {userId}");
                  return Task.CompletedTask;
              }
          }
      };
  });
  ```
</Accordion>

***

## Additional Resources

<CardGroup cols={3}>
  <Card title="SDK Documentation" icon="book" href="https://github.com/auth0/aspnetcore-api">
    Complete SDK documentation and API reference
  </Card>

  <Card title="Migration Guide" icon="arrow-right-arrow-left" href="https://github.com/auth0/aspnetcore-api/blob/master/MIGRATION.md">
    Migrate from JWT Bearer authentication
  </Card>

  <Card title="Code Examples" icon="code" href="https://github.com/auth0/aspnetcore-api/blob/master/EXAMPLES.md">
    Comprehensive code examples and patterns
  </Card>

  <Card title="DPoP Documentation" icon="shield" href="https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop">
    Learn about proof-of-possession security
  </Card>

  <Card title="Token Best Practices" icon="key" href="https://auth0.com/docs/secure/tokens/token-best-practices">
    Security best practices for tokens
  </Card>

  <Card title="Community Forum" icon="comments" href="https://community.auth0.com/">
    Get help from the Auth0 community
  </Card>
</CardGroup>

***

## Common Issues

<AccordionGroup>
  <Accordion title="401 Unauthorized - Invalid audience">
    **Problem:** Token validation fails with audience mismatch error.

    **Solution:** Ensure the `Audience` in `appsettings.json` exactly matches the Identifier of your Auth0 API. The audience claim in the token must match this value.

    ```json theme={null}
    {
      "Auth0": {
        "Audience": "https://my-api"  // Must match Auth0 API Identifier
      }
    }
    ```
  </Accordion>

  <Accordion title="401 Unauthorized - Invalid issuer">
    **Problem:** Token validation fails with issuer error.

    **Solution:** Verify your Domain is correct and does not include `https://`. The library automatically constructs the authority as `https://{Domain}`.

    ```json theme={null}
    {
      "Auth0": {
        "Domain": "your-tenant.auth0.com"  // No https://
      }
    }
    ```
  </Accordion>

  <Accordion title="Configuration values not found">
    **Problem:** `ArgumentNullException: Value cannot be null. (Parameter 'Domain')` or similar.

    **Solution:** Ensure `appsettings.json` contains the Auth0 section with Domain and Audience values. Check that configuration is being read correctly:

    ```csharp theme={null}
    builder.Services.AddAuth0ApiAuthentication(options =>
    {
        options.Domain = builder.Configuration["Auth0:Domain"]
            ?? throw new InvalidOperationException("Auth0:Domain is required");
        options.JwtBearerOptions = new JwtBearerOptions
        {
            Audience = builder.Configuration["Auth0:Audience"]
                ?? throw new InvalidOperationException("Auth0:Audience is required")
        };
    });
    ```
  </Accordion>

  <Accordion title="HTTPS certificate errors in development">
    **Problem:** SSL/TLS certificate errors when running locally.

    **Solution:** Trust the development certificate:

    ```bash theme={null}
    dotnet dev-certs https --trust
    ```

    Or generate a new certificate:

    ```bash theme={null}
    dotnet dev-certs https --clean
    dotnet dev-certs https --trust
    ```
  </Accordion>

  <Accordion title="Middleware order issues">
    **Problem:** Authentication not working despite correct configuration.

    **Solution:** Ensure middleware is in the correct order. `UseAuthentication()` must come before `UseAuthorization()`:

    ```csharp theme={null}
    app.UseAuthentication();  // Must be before UseAuthorization
    app.UseAuthorization();
    app.MapControllers();
    ```
  </Accordion>

  <Accordion title="Scopes not working in authorization policies">
    **Problem:** Scope-based authorization policies always fail.

    **Solution:** Ensure your access token includes the required scopes. When requesting a token, specify the scopes:

    ```bash theme={null}
    curl --request POST \
      --url https://YOUR_DOMAIN/oauth/token \
      --data '{"client_id":"...","client_secret":"...","audience":"...","grant_type":"client_credentials","scope":"read:messages write:messages"}'
    ```

    Also verify scopes are defined in your Auth0 API settings (Dashboard → APIs → Your API → Permissions).
  </Accordion>
</AccordionGroup>

***

## Sample Application

A complete sample application demonstrating all features is available in the SDK repository.

<Card title="Playground Application" icon="github" href="https://github.com/auth0/aspnetcore-api/tree/master/Auth0.AspNetCore.Authentication.Api.Playground">
  Includes public and protected endpoints, DPoP support, Swagger UI integration, and Postman collection
</Card>

Clone and run:

```bash theme={null}
git clone https://github.com/auth0/aspnetcore-api.git
cd aspnetcore-api/Auth0.AspNetCore.Authentication.Api.Playground
# Update appsettings.json with your Auth0 configuration
dotnet run
```
