ZanShield.Sdk 1.0.0

dotnet add package ZanShield.Sdk --version 1.0.0
                    
NuGet\Install-Package ZanShield.Sdk -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="ZanShield.Sdk" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZanShield.Sdk" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ZanShield.Sdk" />
                    
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 ZanShield.Sdk --version 1.0.0
                    
#r "nuget: ZanShield.Sdk, 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 ZanShield.Sdk@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=ZanShield.Sdk&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ZanShield.Sdk&version=1.0.0
                    
Install as a Cake Tool

ZanShield SDK for .NET

Add ZanShield multi-factor authentication to your system's login. ZanShield is the authentication service run by eGAZ (eGovernment Authority Zanzibar).

Your system checks the user's password as usual, then hands them to ZanShield for the second factor. ZanShield decides everything from there: whether the user sets up their first method or verifies an existing one, and which methods (authenticator app, security key, email, SMS) your system allows. It then sends the user back to you with a signed acknowledgement. This library builds the ticket you send and checks the acknowledgement you get back.

Install

dotnet add package ZanShield.Sdk

Requires .NET 8 or later. No dependencies beyond .NET itself. Works in trimmed and native-AOT apps.

Before you start

Your institution admin registers your system in the ZanShield administration console. You get:

  • your system code (e.g. PAYROLL01) and institution code
  • your system's private key (shown once; keep it on your server only, never in a browser or mobile app)
  • ZanShield's engine public key (the admin console's "Download ZanShield public key" button)
  • the portal address, e.g. https://portal.zanshield.devtech.co.tz

The redirect URI you register is where ZanShield sends users back to.

Usage

Create one ZanShieldClient and share it; it is thread-safe. In ASP.NET Core, register it as a singleton:

using ZanShield.Sdk;

builder.Services.AddSingleton(new ZanShieldClient(
    "PAYROLL01",
    "EGAZ",
    PemKeys.LoadPrivateKey(File.ReadAllText("/secure/zanshield-private.pem")),
    PemKeys.LoadPublicKey(File.ReadAllText("/secure/zanshield-engine-public.pem"))));
// 1. After the user's password is correct. fullName and mobile are optional;
//    without a mobile number the user can't choose SMS codes.
string ticket = zanShield.CreateTicket(user.Id, user.Email, user.FullName, user.Phone);
return Redirect(ZanShieldClient.PortalUrl("https://portal.zanshield.devtech.co.tz", ticket));

// 2. At your redirect URI, ZanShield sends the user back with ?ticket=...
try
{
    TicketPayload ack = zanShield.AcceptAcknowledgement(Request.Query["ticket"]!);
    await SignInAsync(ack.UserId!);
}
catch (AcknowledgementRejectedException e)
{
    // Genuine, but must not sign in: e.Reason is NotAuthenticated, Expired or Replayed.
    return ShowError(e.Acknowledgement.Message ?? e.Message);
}
// Any other ZanShieldException means it isn't a valid ZanShield acknowledgement at all.

AcceptAcknowledgement does every check your callback needs before it starts a session. If any check fails it throws and returns nothing:

  1. The ticket decrypts with your key and is signed by ZanShield. If not, it throws ZanShieldException, and you must never trust such a ticket.
  2. ResponseCode is 9000 and IsAuthenticated is true.
  3. It's fresh: issued less than 3 minutes ago, configurable with ZanShieldClientOptions.MaxAcknowledgementAge.
  4. Its TxnId hasn't been used before, so a leaked callback URL can't be replayed into a second session.

More than one server

By default, used transaction IDs are remembered in memory, which protects a single process. If your application runs on several servers, implement ITxnIdStore on something they share:

public sealed class RedisTxnIdStore(IDatabase redis) : ITxnIdStore
{
    public bool MarkUsed(string txnId, DateTimeOffset keepUntil) =>
        redis.StringSet($"zanshield:txn:{txnId}", 1, keepUntil - DateTimeOffset.UtcNow, When.NotExists);
}

var zanShield = new ZanShieldClient(systemCode, institutionCode, privateKey, enginePublicKey,
    new ZanShieldClientOptions { TxnIdStore = new RedisTxnIdStore(redis) });

Response codes

ResponseCodes has every code ZanShield uses. On an acknowledgement, only ResponseCodes.Success (9000) means the user verified.

License

Apache-2.0

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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.
  • net8.0

    • No dependencies.

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 77 10/10/2026