SignedChannel 0.3.1
See the version list below for details.
dotnet add package SignedChannel --version 0.3.1
NuGet\Install-Package SignedChannel -Version 0.3.1
<PackageReference Include="SignedChannel" Version="0.3.1" />
<PackageVersion Include="SignedChannel" Version="0.3.1" />
<PackageReference Include="SignedChannel" />
paket add SignedChannel --version 0.3.1
#r "nuget: SignedChannel, 0.3.1"
#:package SignedChannel@0.3.1
#addin nuget:?package=SignedChannel&version=0.3.1
#tool nuget:?package=SignedChannel&version=0.3.1
SignedChannel
A session-bound signed channel between a browser and an ASP.NET Core server:
- Browser → server is signed HTTP. Every request carries a signature made with a key pair generated per session, so a request cannot be forged or replayed.
- Server → browser is SignalR push, on a presence-tracked connection — so the server knows when a tab goes away.
- Business logic is actions, not controllers. You write classes implementing
ISecureWebBrowserAction<TRequest, TResponse>; they are resolved by wire name through a namespace convention. No route table, no per-endpoint auth plumbing.
| Package | Registry | What it is |
|---|---|---|
SignedChannel |
NuGet | The server half: handshake, dispatcher, presence hub, push |
SignedChannel.MongoDb |
NuGet | MongoDB session storage |
signed-channel-client |
npm | The browser half, framework-agnostic |
All three version in lockstep from one git tag, so the client and server halves of the protocol cannot drift apart.
Getting started
builder.Services.BindSignedChannelConfiguration(builder.Configuration);
builder.Services.AddSignedChannel(options =>
{
options.ActionAssembly = typeof(Program).Assembly;
options.RootNamespace = "MyApp";
options.DevActionPrefix = "MyApp.Dev."; // keep the trailing dot
});
builder.Services.AddSignedChannelMongoDb(); // or your own IChannelSessionStore
app.MapSignedChannelHub(); // must come before any SPA fallback route
app.MapSignedChannel();
ActionAssembly and RootNamespace have no sensible default and are validated at startup.
Action lookup scans the assembly you name — if it scanned its own, it would find nothing and
every action would answer 404 with nothing in the logs to say why.
An action is just a class in the right place. The wire name "Profile.GetName" resolves to
MyApp.Profile.Actions.WebApp.GetName.GetNameAction:
public sealed class GetNameAction : ISecureWebBrowserAction<GetNameRequest, GetNameResponse>
{
// Constructor dependencies are injected — no DI registration needed.
public WebBrowserActionsValidationResult ValidateFromWebBrowser(...) => new() { IsValid = true };
public Task<bool> HasAccess(...) => Task.FromResult(userId is not null);
public async Task<GetNameResponse> ProcessMessageFromWebBrowserAsync(...) { ... }
}
Signing a session in
The channel never decides who someone is. Authenticate however you like — passkeys, OIDC, a magic link — then tell it:
await sessionStore.SetUserIdAsync(sessionId, yourOwnUserId);
The user id is opaque: echoed to actions, used to decide whether a request counts as signed in,
never interpreted. That is what lets a confidential OIDC client hand over the sub from its own
callback and get an authenticated channel out of it.
Optional hooks
Register any of these and the channel calls them; leave them out and it does not.
| Interface | Called for |
|---|---|
IChannelSessionObserver |
a session registering — per-browser bookkeeping |
IChannelActivityRecorder |
a completed action — your audit trail |
ISessionDeviceResolver |
the device behind a signed-in session |
IPresenceObserver |
connections opening and closing |
IConnectionChangeNotifier |
a signed-in session losing a tab |
Status
Early — 0.x, API not yet stable. The code is extracted from a production implementation
rather than written fresh, so the protocol is settled even while the C# surface still moves.
Licence
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FluentValidation (>= 12.1.1)
- Meyn.Utilities (>= 10.2.0)
- PublicKeyUtils (>= 10.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on SignedChannel:
| Package | Downloads |
|---|---|
|
SignedChannel.MongoDb
MongoDB session storage for SignedChannel. Provides IChannelSessionStore on top of MongoDbService, and is open for inheritance so an application can keep its own per-session state in the same document. |
GitHub repositories
This package is not used by any popular GitHub repositories.