# Remaining Lower-Priority Gaps — Design Document

**Goal:** Resolve all remaining lower-priority gaps from differences.md with full Go parity, bringing the .NET NATS server to feature completeness for single-server (non-clustered) deployments.

**Approach:** Full Go parity — implement all listed gaps including JWT authentication, subject mapping, OCSP, and quick wins.

---

## 1. JWT Authentication

The largest component. NATS uses standard JWT encoding (base64url header.payload.signature) with Ed25519 signing via the `nats-io/jwt/v2` Go library.

### New Files

- **`Auth/Jwt/NatsJwt.cs`** — JWT decode/encode utilities. Base64url parsing, header extraction, Ed25519 signature verification via NATS.NKeys. Detects JWT by `"eyJ"` prefix.
- **`Auth/Jwt/UserClaims.cs`** — User claim record: `Subject` (nkey), `Issuer` (account nkey), `IssuerAccount` (scoped signer), `Name`, `Tags`, `BearerToken`, `Permissions` (pub/sub allow/deny), `ResponsePermission`, `Src` (allowed CIDRs), `Times` (time-based access), `AllowedConnectionTypes`, `IssuedAt`, `Expires`.
- **`Auth/Jwt/AccountClaims.cs`** — Account claim record: `Subject`, `Issuer` (operator nkey), `SigningKeys`, `Limits`, `Exports`, `Imports`.
- **`Auth/Jwt/PermissionTemplates.cs`** — Template expansion for all 6 mustache-style templates:
  - `{{name()}}` → user's Name
  - `{{subject()}}` → user's Subject (nkey)
  - `{{tag(name)}}` → user tags matching `name:` prefix
  - `{{account-name()}}` → account display name
  - `{{account-subject()}}` → account nkey
  - `{{account-tag(name)}}` → account tags matching prefix
  - Cartesian product applied for multi-value tags.
- **`Auth/Jwt/AccountResolver.cs`** — `IAccountResolver` interface (`FetchAsync`, `StoreAsync`, `IsReadOnly`) + `MemAccountResolver` in-memory implementation.
- **`Auth/JwtAuthenticator.cs`** — Implements `IAuthenticator`. Flow: decode user JWT → resolve account → verify Ed25519 signature against nonce → expand permission templates → build `NkeyUser` → validate source IP + time restrictions → check user revocation.

### Modified Files

- **`Auth/Account.cs`** — Add `Nkey`, `Issuer`, `SigningKeys` (Dictionary), `RevokedUsers` (ConcurrentDictionary<string, long>).
- **`NatsOptions.cs`** — Add `TrustedKeys` (string[]), `AccountResolver` (IAccountResolver).
- **`NatsClient.cs`** — Pass JWT + signature from CONNECT opts to authenticator.

### Design Decisions

- No external JWT NuGet — NATS JWTs are simple enough to parse inline (base64url + System.Text.Json + Ed25519 via NATS.NKeys).
- `MemAccountResolver` only — URL/directory resolvers are deployment infrastructure.
- User revocation: `ConcurrentDictionary<string, long>` on Account (nkey → issuedAt; JWTs issued before revocation time are rejected).
- Source IP validation via `System.Net.IPNetwork.Contains()` (.NET 8+).

---

## 2. Subject Mapping / Transforms

Port Go's `subject_transform.go`. Configurable source pattern → destination template with function tokens.

### New File

- **`Subscriptions/SubjectTransform.cs`** — A transform has a source pattern (with wildcards) and a destination template with function tokens. On match, captured wildcard values are substituted into the destination.

### Transform Functions

| Function | Description |
|----------|-------------|
| `{{wildcard(n)}}` / `$n` | Replace with nth captured wildcard token (1-based) |
| `{{partition(num,tokens...)}}` | FNV-1a hash of captured tokens mod `num` |
| `{{split(token,delim)}}` | Split captured token by delimiter into subject tokens |
| `{{splitFromLeft(token,pos)}}` | Split token into two at position from left |
| `{{splitFromRight(token,pos)}}` | Split token into two at position from right |
| `{{sliceFromLeft(token,size)}}` | Slice token into fixed-size chunks from left |
| `{{sliceFromRight(token,size)}}` | Slice token into fixed-size chunks from right |
| `{{left(token,len)}}` | Take first `len` chars |
| `{{right(token,len)}}` | Take last `len` chars |

### Integration

- `NatsOptions.SubjectMappings` — `Dictionary<string, string>` of source→destination rules.
- Transforms compiled at config time into token operation lists (no runtime regex).
- Applied in `NatsServer.DeliverMessage` before subject matching.
- Account-level mappings for import/export rewriting.

---

## 3. OCSP Support

Two dimensions: peer verification (client cert revocation checking) and stapling (server cert status).

### New File

- **`Tls/OcspConfig.cs`** — `OcspMode` enum (`Auto`, `Always`, `Must`, `Never`) + `OcspConfig` record with `Mode` and `OverrideUrls`.

### Peer Verification

- Modify `TlsConnectionWrapper` to set `X509RevocationMode.Online` when `OcspPeerVerify` is true.
- Checks CRL/OCSP during TLS handshake for client certificates.

### OCSP Stapling

- Build `SslStreamCertificateContext.Create(cert, chain, offline: false)` at startup — .NET fetches OCSP response automatically.
- Pass to `SslServerAuthenticationOptions.ServerCertificateContext`.
- `Must` mode: verify OCSP response obtained; fail startup if not.

### Modified Files

- `NatsOptions.cs` — `OcspConfig` and `OcspPeerVerify` properties.
- `TlsConnectionWrapper.cs` — Peer verification in cert validation callback.
- `NatsServer.cs` — `SslStreamCertificateContext` with OCSP at startup.
- `VarzHandler.cs` — Populate `TlsOcspPeerVerify` field.

---

## 4. Quick Wins

### A. Windows Service Integration

- Add `Microsoft.Extensions.Hosting.WindowsServices` NuGet.
- Detect `--service` flag in `Program.cs`, call `UseWindowsService()`.
- .NET generic host handles service lifecycle automatically.

### B. Per-Subsystem Log Control

- `NatsOptions.LogOverrides` — `Dictionary<string, string>` mapping namespace→level.
- CLI: `--log_level_override "NATS.Server.Protocol=Trace"` (repeatable).
- Serilog: `MinimumLevel.Override(namespace, level)` per entry.

### C. Per-Client Trace Mode

- `TraceMode` flag in `ClientFlagHolder`.
- When set, parser receives logger regardless of global `options.Trace`.
- Connz response includes `trace` boolean per connection.

### D. Per-Account Stats

- `long _inMsgs, _outMsgs, _inBytes, _outBytes` on `Account` with `Interlocked`.
- `IncrementInbound(long bytes)` / `IncrementOutbound(long bytes)`.
- Called from `DeliverMessage` (outbound) and message processing (inbound).
- `/accountz` endpoint returns per-account stats.

### E. TLS Certificate Expiry in /varz

- In `VarzHandler`, read server TLS cert `NotAfter`.
- Populate existing `TlsCertNotAfter` field.

### F. differences.md Update

- Mark all resolved features as Y with notes.
- Update summary section.
- Correct any stale entries.

---

## Task Dependencies

```
Independent (parallelizable):
  - JWT Authentication (#23)
  - Subject Mapping (#24)
  - OCSP Support (#25)
  - Windows Service (#26)
  - Per-Subsystem Logging (#27)
  - Per-Client Trace (#28)
  - Per-Account Stats (#29)
  - TLS Cert Expiry (#30)

Dependent:
  - Update differences.md (#31) — blocked by all above
```

Most tasks can run in parallel since they touch different files. JWT and Subject Mapping are the two largest. The quick wins (26-30) are all independent of each other and of the larger tasks.
