C# and VB.NET
Add licensing to a .NET app with the PWFAuth NuGet package.
The PWFAuth NuGet package handles the encryption, the heartbeat and the kill switch for you. It targets .NET Standard 2.0 and .NET 8, so it works in WinForms, WPF and console apps on .NET Framework 4.6.2 and newer, in C# and in VB.NET.
Install
dotnet add package PWFAuthIn Visual Studio: Project → Manage NuGet Packages, search for PWFAuth, install.
The package talks only to https://pwfauth.com; any other server address is refused.
Keep the secret out of your code
Read the app secret at start-up instead of writing it in the source, for example from App.config or an environment variable:
<appSettings>
<add key="PWFAuthAppSecret" value="YOUR_64_CHARACTER_APP_SECRET" />
</appSettings>Sign in and start the heartbeat
Imports PWFAuth
Public Class FormLogin
Public Shared Client As PwfClient
Private Async Sub btnSignIn_Click(sender As Object, e As EventArgs) Handles btnSignIn.Click
Client = New PwfClient(ConfigurationManager.AppSettings("PWFAuthAppSecret"))
AddHandler Client.SessionEnded, Sub(s, args)
' already on the UI thread
MessageBox.Show(args.Message, "Signed out")
Application.Exit()
End Sub
btnSignIn.Enabled = False
Dim login = Await Client.LoginAsync(txtKey.Text.Trim())
btnSignIn.Enabled = True
If Not login.Success Then
lblStatus.Text = login.Message ' written for the customer
Return
End If
Client.StartHeartbeat() ' the kill switch: never skip it
FormMain.Show()
Hide()
End Sub
End Classusing PWFAuth;
var client = new PwfClient(secret);
client.SessionEnded += (s, e) =>
{
MessageBox.Show(e.Message, "Signed out");
Application.Exit();
};
var login = await client.LoginAsync(txtKey.Text.Trim());
if (!login.Success) { lblStatus.Text = login.Message; return; }
client.StartHeartbeat();SessionEnded fires when the key is banned, paused, expired, deleted or reset, when you end the session from the panel, when the app goes into maintenance, and when the server cannot be reached three times in a row. e.IsNetworkFailure tells the last case apart.
Show the licence
The sign-in reply carries everything about the key:
Dim user As JsonElement
If login.TryGetProperty("user", user) Then
Dim exp As JsonElement
If user.TryGetProperty("expires_at", exp) AndAlso exp.ValueKind = JsonValueKind.String Then
lblLicence.Text = "Expires " & DateTime.Parse(exp.GetString()).ToLocalTime().ToString("g")
Else
lblLicence.Text = "Lifetime licence" ' expires_at is null for lifetime keys
End If
End IfOther fields: user.key_type, user.days_remaining, app.name, app.version, app.message (your welcome message), features, texts and slides.
Move the licence to a new PC
When the key belongs to another PC, offer to move it. This works when self-service is on for the app (see HWID resets):
If Not login.Success AndAlso (login.ErrorCode = PwfErrorCodes.HwidMismatch OrElse
login.ErrorCode = PwfErrorCodes.DeviceLimit) Then
If MessageBox.Show(login.Message & vbCrLf & "Move your licence to this PC?", "PWF Auth",
MessageBoxButtons.YesNo) = DialogResult.Yes Then
Dim reset = Await Client.ResetHardwareIdAsync(key, "Moved to a new PC")
MessageBox.Show(reset.Message)
If reset.Success Then login = Await Client.LoginAsync(key)
End If
End IfCustomer accounts
Instead of a key, a customer can sign in with a username and password (see Users). The session and the heartbeat work exactly as with a key:
Dim login = Await Client.AccountLoginAsync(username, password)
If Not login.Success Then
MessageBox.Show(login.Message) ' INVALID_CREDENTIALS, BANNED, PAUSED, EXPIRED, HWID_MISMATCH …
Return
End If
Client.StartHeartbeat()Sign-up, keys and password changes, when sign-up is on for the app:
Dim r = Await Client.RegisterAccountAsync(username, password, email) ' REGISTRATION_DISABLED when sign-up is off
If r.ErrorCode = PwfErrorCodes.KeyRequired Then ' "Sign-up needs a licence key" is on
r = Await Client.RegisterAccountWithKeyAsync(username, password, key, email)
End If
Dim more = Await Client.RedeemKeyAsync(key) ' signed in: adds the key's time
Dim back = Await Client.RedeemKeyAsync(username, password, key) ' signed out, works after expiry too
Dim c = Await Client.ChangeAccountPasswordAsync(username, currentPassword, newPassword)A changed password signs out every copy using the account, the one that changed it too: sign in again with the new password. An account is bound to one PC; when it moves, you reset its machine in Users.
RegisterAccountWithKeyAsync and RedeemKeyAsync need version 1.3.0 of the package or newer. A key spent on an account cannot sign in on its own any more: LoginAsync answers KEY_REDEEMED.Sign out
Await Client.LogoutAsync() ' ends the session; the key stays bound to this PC
Client.Dispose()More calls
| Call | Does |
|---|---|
CheckKeyAsync(key) | Reads a key's status without signing in or using a machine seat. |
CreateTrialAsync() | A free trial key for this PC, when trials are on. |
GetAppInfoAsync() | App name, version, download link, maintenance state. |
GetTextsAsync() / GetSlidesAsync() | Remote texts and announcement slides. |
CheckUpdateAsync(version) | Is there a newer build? See Updates. |
A complete example
A ready console program in VB.NET that does all of the above (sign in with a key or an account, sign-up, password change, saved key, trial, moving a licence, licence card, updates, live kill switch) is available on request: ask us on Telegram.
Something missing or unclear? Tell us on Telegram.