---
title: "sdk/dotnet"
description: ".NET 8 server SDK for networkless JWT verification, ASP.NET Core request authentication, and webhook signature validation."
locale: "en"
---

> Documentation Index
> Fetch the relevant documentation index at: https://xid.fngx.org/sdks/llms.txt
> Use this file to discover all available pages before exploring further.

# sdk/dotnet

## Status

Implemented and verified locally. Real IdP round-trip verification (JWKS fetch, token sign/verify against a live XID instance) has not been performed yet and must be completed before production use.

XID publishes no packages to any registry. This SDK is distributed as source in the XID repository; use it from a checkout of the repository.

Request authentication is Bearer-only by default. An application-owned JWT cookie is read only when its exact name is configured. The opaque \_\_Host-xid.rt.\* Core cookie is never scanned or verified locally; exchange it by forwarding the complete Cookie header to exact same-origin POST /v1/sessions/token with redirects disabled, and accept only a response containing the token field.

## Install

.NET 8 target required.

```xml
<ItemGroup>
  <ProjectReference Include="../xid/sdk/dotnet/Xid.csproj" />
</ItemGroup>
```

## ASP.NET Core setup (recommended)

```csharp
// Program.cs
using Xid;

builder.Services.AddXid(options =>
{
options.Issuer   = "https://xid.dev";
options.Audience = "your-client-id"; // optional
});
```

## Authenticate a request

```csharp
// Controller / Minimal API
public class MyController(XidClient xid) : ControllerBase
{
[HttpGet("/me")]
public async Task<IActionResult> GetMe()
{
    var auth = await xid.AuthenticateRequestAsync(
        authorizationHeader: Request.Headers.Authorization);

    if (!auth.Authenticated)
        return Unauthorized(auth.Reason);

    return Ok(new { sub = auth.Claims!.Sub, email = auth.Claims.Email });
}

private Task<string> ExchangeSessionAsync() => xid.ExchangeSessionTokenAsync(
    $"{Request.Scheme}://{Request.Host}{Request.Path}",
    Request.Headers.Cookie.ToString());
}
```

## Verify token directly

```csharp
using Xid;

var client = new XidClient(new XidOptions { Issuer = "https://xid.dev" });

try
{
var claims = await client.VerifyTokenAsync("eyJ...");
Console.WriteLine($"sub={claims.Sub} email={claims.Email}");
}
catch (TokenVerificationException ex)
{
Console.WriteLine($"Invalid token: {ex.Message}");
}
```

## Verify webhook

```csharp
app.MapPost("/webhooks/xid", async (HttpRequest req, XidClient xid) =>
{
using var ms = new MemoryStream();
await req.Body.CopyToAsync(ms);
var body = ms.ToArray();

var headers = new Dictionary<string, string>
{
    ["svix-id"]        = req.Headers["svix-id"].ToString(),
    ["svix-timestamp"] = req.Headers["svix-timestamp"].ToString(),
    ["svix-signature"] = req.Headers["svix-signature"].ToString(),
};

var webhookSecret = Environment.GetEnvironmentVariable("XID_WEBHOOK_SECRET")
    ?? throw new InvalidOperationException("XID_WEBHOOK_SECRET is required");

try
{
    var webhook = xid.VerifyWebhook(body, headers, secret: webhookSecret);
    return Results.Ok();
}
catch (WebhookVerificationException ex)
{
    return Results.BadRequest(ex.Message);
}
});
```

## XidOptions

| Property | Default | Description |
| --- | --- | --- |
| `Issuer` | required | XID issuer URL |
| `Audience` | `null` | Expected aud claim; null skips validation |
| `JwksTtl` | 1 hour | JWKS in-memory cache TTL |
| `SessionCookieName` | `disabled` | Application-owned JWT cookie name; disabled unless explicitly configured |
| `ClockSkew` | 5 minutes | JWT exp/nbf clock skew tolerance |
| `WebhookToleranceWindow` | 5 minutes | Webhook replay prevention window |

## XidClient API

| Method | Description |
| --- | --- |
| `VerifyTokenAsync(token, ct)` | Verify JWT string; throws `TokenVerificationException` on failure. |
| `AuthenticateRequestAsync(authHeader, cookies, ct)` | Extract and verify token; returns `AuthStatus`; does not throw. |
| `VerifyWebhook(payload, headers, secret)` | Validate webhook signature; throws `WebhookVerificationException` on failure. Synchronous. |

## Platform notes

- Uses `Microsoft.IdentityModel.Tokens` and `System.IdentityModel.Tokens.Jwt` 8.x. ES256 is primary; RS256 and PS256 are supported.
- `AddXid()` registers `XidClient` as a singleton and wires `IHttpClientFactory` for JWKS fetching.
- Exception hierarchy: `XidException` -&gt; `JwksException`, `TokenVerificationException`, `WebhookVerificationException`.

Source: https://xid.fngx.org/sdks/dotnet/index.mdx
