Ahwoo.SessionTickets.Server 1.0.0

Prefix Reserved
dotnet add package Ahwoo.SessionTickets.Server --version 1.0.0
                    
NuGet\Install-Package Ahwoo.SessionTickets.Server -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ahwoo.SessionTickets.Server" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ahwoo.SessionTickets.Server" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Ahwoo.SessionTickets.Server" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ahwoo.SessionTickets.Server --version 1.0.0
                    
#r "nuget: Ahwoo.SessionTickets.Server, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ahwoo.SessionTickets.Server@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ahwoo.SessionTickets.Server&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Ahwoo.SessionTickets.Server&version=1.0.0
                    
Install as a Cake Tool

Ahwoo.SessionTickets.Server

Use this package to identify the Ahwoo account that a joining player is signed in to.

The player signs in to the Ahwoo desktop client, a separate Windows application. The joining game asks that client to mint a session ticket, a short-lived signed assertion of the player's identity. The game mints the ticket with Ahwoo.SessionTickets.Client and sends it to your game server. This package verifies the ticket against Ahwoo's published public signing keys and gives your game server a stable Ahwoo profile ID.

Your game server holds no Ahwoo secret and never sees the player's access token. Anyone can therefore operate a game server without holding Ahwoo credentials.

dotnet add package Ahwoo.SessionTickets.Server

How the exchange works

  1. The player's game connects to your game server. Your game server generates a nonce, a single-use random challenge value, and sends it to the game.
  2. The game asks the Ahwoo desktop client on the player's computer to mint a ticket bound to that nonce.
  3. The game sends the ticket to your game server over the game's own network connection. Ahwoo provides no transport for this step.
  4. Your game server verifies the ticket and reads the player's Ahwoo profile ID.

Verifying a ticket

using Ahwoo.SessionTickets.Server;

// Create one verifier per process and keep it for the lifetime of the process.
// The verifier caches Ahwoo's signing keys.
private readonly SessionTicketVerifier _ahwoo = new();

async Task AdmitAsync(Connection connection, CancellationToken cancellationToken)
{
    var nonce = SessionTicketNonce.Create();
    var ticket = await connection.ChallengeAsync(nonce);

    var result = await _ahwoo.VerifyAsync(ticket, nonce, cancellationToken);
    if (!result.IsValid)
    {
        connection.Refuse(result.Rejection);
        return;
    }

    Guid ahwooProfileId = result.Ticket.ProfileId;
    if (BanList.Contains(ahwooProfileId))
        connection.Refuse();
}

VerifyAsync checks the signature, the issuer, the audience, the expiry, and the nonce that your game server sent. VerifyAsync returns a result instead of throwing an exception, because a bad ticket is ordinary traffic on a public server.

VerifyAsync throws SessionTicketKeysUnavailableException, in Ahwoo.SessionTickets.Server.Exceptions, only when it cannot fetch Ahwoo's signing keys at all. Refuse the connection and retry. Never admit a player whose ticket your game server has not verified.

Rejection reasons

Log result.Rejection to record why a ticket failed. Every value calls for the same operational response: refuse the connection. Add using Ahwoo.SessionTickets.Server.Models; when your code names the enum values rather than only logging them.

Reason Cause
SignatureNotTrusted Ahwoo did not sign the ticket with a published key, or the signature uses the wrong algorithm.
NonceMismatch The game minted the ticket against a different challenge, so the ticket belongs to another connection attempt.
Expired The ticket is older than its life of about 120 seconds. Ask the game to mint a new ticket.
NotYetValid Your game server's clock is behind Ahwoo's clock by more than the configured skew.
UntrustedIssuer Something other than the configured Ahwoo API issued the token.
WrongAudience The token's audience is something other than an Ahwoo session ticket.
ClaimsMissing The ticket is signed and current, but it carries no usable identity.
Malformed The verifier cannot read the ticket, or validation failed for a reason with no more specific value.

What the security depends on

Use one nonce per connection attempt. Generate each nonce with SessionTicketNonce.Create(), and consume it as soon as your game server accepts a ticket against it. Never accept two tickets for one outstanding nonce, and never reuse a nonce across connections. The nonce is what stops an attacker from replaying a ticket harvested elsewhere.

Key your bans and player records on ProfileId. ProfileId is a Guid, and it stays the same for the life of the Ahwoo account. DisplayName is only the name that the player used at mint time, and the player can change it.

Keep the verifier alive for the lifetime of the process. The verifier caches Ahwoo's signing keys and fetches them again when a ticket names a key that the cache does not hold. This is how the verifier survives a key rotation. A verifier per connection defeats the cache, and it calls the key endpoint on every join.

Optionally, store each accepted result.Ticket.TicketId for a few minutes, and refuse a ticket that repeats one. This check backstops a broken nonce lifecycle. It does not replace the nonce check, and it has no effect across a fleet of game servers unless those servers share the store.

What a ticket does not tell you

  • A ticket asserts identity only. It says nothing about game ownership or entitlements.
  • A banned player can create a new Ahwoo account and receive a new ProfileId.
  • A ticket is not bound to the game server that it was minted for. A hostile game server can relay a visitor's ticket to another game server within the ticket's life of about 120 seconds. Binding tickets to a destination is future work.

Configuration

This package requires no configuration to verify tickets against Ahwoo's live API. Pass options to point the verifier at a different Ahwoo API.

Option Default Description
ApiBaseUrl https://api.ahwoo.com The Ahwoo API that mints the tickets. Sets both the issuer that the verifier trusts and the endpoint it fetches signing keys from
ClockSkew 30 seconds Tolerance for clock drift between your game server and Ahwoo
KeyRefreshCooldown 30 seconds Shortest interval between key fetches, so that tickets naming unknown keys cannot pull the key endpoint repeatedly
var verifier = new SessionTicketVerifier(new SessionTicketVerifierOptions
{
    ApiBaseUrl = new Uri("https://api.ahwoo.example")
});

The constructor also accepts an HttpClient if your game server manages its own. Use the ISessionTicketVerifier interface to substitute the verifier in your own tests.

Support

Email contact@ahwoo.com with questions or bug reports.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 143 8/19/2026