pyrad

A pure-Python library for building RADIUS clients and servers, covering authentication, accounting, and Change-of-Authorization out of the box.

Library
PyPI
v2.5.4
310stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
57/100Fair
Development Activity36
Maintenance32
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture75
Code Quality78
Innovation55
Learning Curve85

pyrad is a pure-Python implementation of the RADIUS protocol described in RFC 2865 and RFC 2866. It handles the low-level details of building, encoding, and decoding RADIUS packets so callers can focus on the authentication, accounting, or Change-of-Authorization (CoA) logic itself rather than wire-format bit-twiddling.

The library ships both client and server building blocks, in synchronous (select/poll-based) and asyncio flavors, sharing a common Host base and a pluggable Dictionary system that loads vendor-specific RADIUS attribute definitions (including FreeRADIUS-format dictionary files) without any code changes. It’s maintained by the pyradius organization, has been in production use for over a decade, and remains the go-to option when a project needs to speak RADIUS from Python without pulling in a full C-extension binding.

What You Get

  • A Client class for sending Access, Accounting, and CoA requests with automatic retries and timeouts over UDP
  • A Server base class (plus an asyncio DatagramProtocolServer variant) for building RADIUS servers that authenticate and account for NAS devices
  • A Packet/AuthPacket/AcctPacket/CoAPacket hierarchy that preserves RADIUS attribute ordering and handles request/response authenticator and Message-Authenticator verification
  • A Dictionary loader compatible with FreeRADIUS-style attribute dictionaries, including vendor-specific attribute (VSA) support
  • Built-in EAP-MD5 challenge/response handling inside Client.SendPacket for PAP-style auth flows

Common Use Cases

  • Writing a Python-based RADIUS client to authenticate users or devices against an existing RADIUS/NAS infrastructure
  • Standing up a lightweight test or mock RADIUS server for integration-testing network gear or AAA workflows
  • Sending RADIUS accounting records (start/stop/interim-update) from a captive portal, VPN gateway, or custom NAS
  • Issuing CoA/Disconnect-Message requests to force a session re-authorization or disconnect from Python tooling

Under The Hood

Architecture pyrad is organized as a small protocol stack: dictionary.py/dictfile.py sit at the bottom, parsing FreeRADIUS-style attribute definition files into a lookup table; packet.py builds on that to implement Packet (and its AuthPacket/AcctPacket/CoAPacket subclasses) as an OrderedDict subclass that encodes/decodes the RADIUS wire format and computes request/response authenticators; host.py provides a shared Host base with CreateAuthPacket/CreateAcctPacket/CreateCoAPacket factory methods that both client.py’s Client and server.py’s Server inherit from. The synchronous transport uses select.poll() directly in Client._SendPacket and Server, while client_async.py/server_async.py reimplement the same request/reply cycle on top of asyncio.Protocol. Because both transport variants and proxy.py all construct packets through the shared Host methods, changing the core Packet abstraction would ripple through every module — a layered, moderately coupled design rather than a fully decoupled one.

Tech Stack The library targets Python 3.8+ and has a single runtime dependency, netaddr>=0.8.0, used for IP/CIDR-typed RADIUS attributes; everything else (socket, select, hashlib, hmac, struct, asyncio) comes from the standard library. Packaging uses pyproject.toml with a setuptools backend and a dynamic version pulled from pyrad.__version__. Development tooling is managed via dependency-groups: ruff for linting (alongside a .flake8 config), pytest>=8 with coverage/lcov for testing, and sphinx/sphinx-rtd-theme for docs published to Read the Docs. GitHub Actions run the test suite, CodeQL analysis, and a PyPI publish workflow on release.

Code Quality The pyrad/tests/ directory holds roughly 2,000 lines across eight unittest-based test files, covering packet construction/encoding (test_packet.py, the largest at ~680 lines), dictionary parsing, client and server request/response flows, and utility functions, backed by a mock.py helper and fixture data. Error handling uses explicit, typed exceptions (PacketError, ServerPacketError, Timeout) rather than broad catches or silent failures. Docstrings are dense and epytext-formatted throughout the core modules, and both ruff and a .flake8 config enforce style, with CI running the suite on every push.

What Makes It Unique pyrad’s niche is being a dependency-light, pure-Python implementation that covers both sides of the RADIUS conversation — client and server, synchronous and asyncio — plus CoA/Disconnect-Message support (RFC 5176), in one codebase with a vendor-agnostic, FreeRADIUS-compatible dictionary loader. It isn’t introducing new protocol capabilities beyond the RFCs it implements, but that faithful, actively maintained coverage of an open protocol (rather than a single vendor’s API) is what keeps it the default choice for Python RADIUS work.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search