This revision uses pwfauth 1.5.0. The requirements file installs the PyPI wheel, pinned by version and SHA-256. Versions before 1.3.0 cannot talk to the current server (it signs its replies with a new key), so update older copies.
A guided console tour of the official
pwfauth Python package (version 1.5.0) for
PWF Auth: license keys, the heartbeat and its kill switch,
moving a license to a new PC, update checks, user variables, trials and user accounts. One
numbered section per feature, with coloured results.
Sibling projects:
- a Tkinter desktop app:
pwfauth-python-desktop-sample- the package's own source:
pwfauth-python- the VB.NET and C# examples:
pwfauth-vbnet-examples
pip install -r requirements.txt # the pwfauth packageRequires Python 3.9+.
Configure DEFAULT_APP_SECRET in demo.py before distribution. Never commit the real secret.
python demo.py PWF-XXXX-XXXX-XXXXRun with no argument to be prompted for the key. Options:
| Option | What it does |
|---|---|
--move |
Move the license here without asking when it is bound to another PC |
--seconds N |
Keep the session open N seconds instead of waiting for Enter |
--trial |
Also create a free trial key for this computer |
--accounts |
Also create a throwaway user account |
--trial and --accounts are off by default because they create data in your
application. The server is fixed to https://pwfauth.com; environment overrides are ignored.
Exit codes: 0 done, 1 no secret or key, 2 sign-in refused, 3 no connection
or not the license server, 4 the kill switch ended the session.
| # | Feature | Package call |
|---|---|---|
| 0 | App info: name, version, social links | get_app_info() |
| 1 | Check a key without using a device seat | check_key() |
| 2 | Sign in: bind this PC, open a session | login() |
| 2 | Move the license here when it is bound elsewhere | reset_hardware_id() |
| 3 | Update check, remote texts, slides | check_update(), get_texts(), get_slides() |
| 4 | User variables: values kept on the server for this key | get_variable(), set_variable(), get_variables() |
| 5 | The heartbeat and its kill switch | start_heartbeat(), on_session_ended |
| 6 | Sign out | logout() |
| 7 | Free trial (--trial) |
create_trial() |
| 8 | User accounts (--accounts) |
register_account(), account_login(), change_account_password() |
Section 4 counts how often the key ran the demo, in a user variable called
demo_runs, and lists every variable of the key. Open the key in your panel
(Licences → the key → Variables): the count is there, and a value you change
there is what the demo reads next time. Variables follow the key to a new PC.
During section 5, ban, pause or reset the key in your dashboard: the demo stops
on the next beat, the way a real app should. The callback runs on the heartbeat
thread, so it stops the program with os._exit(); sys.exit() would only end that
thread.
import os, sys
from pwfauth import PwfClient
client = PwfClient(os.environ["PWFAUTH_SECRET"])
def on_session_ended(code, msg): # kill switch: banned, paused, expired, reset...
print(f"Session ended ({code}): {msg}", file=sys.stderr)
os._exit(1) # runs on the heartbeat thread, where sys.exit() would only end that thread
client.on_session_ended = on_session_ended
login = client.login("PWF-XXXX-XXXX-XXXX")
if not login.success:
sys.exit(login.message)
client.start_heartbeat() # keeps the session alive AND enforces the kill switch
# values kept on the server for this key, editable in your panel
client.set_variable("theme", "dark")
theme = client.get_variable("theme") # None when never setThe package also:
- corrects a wrong PC clock by itself, and moving the clock does not dodge the kill switch;
- refuses a reply that claims success without encryption (
PwfSecurityError): it came from a proxy, a hosts-file entry or a fake server.
Full reference: pwfauth.com/docs.
| File | Role |
|---|---|
demo.py |
The guided tour, one function per section |
test_demo.py |
Offline tests: the fixed configuration, and the user-variables section against a stand-in client |
Version 1 of this repository was a hand-written client, pwfauth_client.py, built
on pycryptodome. It did not refuse a fake server's plain "success" and had no
heartbeat loop, so a ban never stopped the app. It is replaced by the official
package, which does both. The old code stays available at the
v1.0.0 tag.
An app secret shipped in a client can be extracted — treat client-side license
checks as a deterrent, not DRM. Keep the secret out of source control; the
demo uses the developer-configured DEFAULT_APP_SECRET.
MIT — see LICENSE.
