PyOTP is a Python library for generating and verifying one-time passwords, implementing HOTP (RFC 4226) and TOTP (RFC 6238) for 2FA or MFA in web applications and other systems. It is useful for server-side OTP support, including generating provisioning URIs for OTP authenticator apps (and parsing those URIs) so users can set up credentials by scanning a QR code.
Project status
- Actively maintained, evidence includes an upstream push on 2026-06-14 and a corresponding PyPI/GitHub tag update, v2.10.0, on 2026-06-14 (4 days before today).
- Apparent update cadence is irregular overall, v2.10.0 arrived in 2026-06-14, but the prior tagged update was v2.9.0 on 2023-07-27, with earlier tags in 2022 and 2021, suggesting long quiet periods punctuated by active development.
AI summary generated
Recent updates
v2.10.0
v2.10.0 focuses on OTP URI parsing correctness and runtime robustness, especially around percent-encoding edge cases. The release also includes Steam OTP generation performance tweaks and adds validation for digest functions that would otherwise cause OTP generation failures.
v2.9.0
v2.9.0 adds Steam-specific support to `parse_uri()` so that `otpauth://...` URLs with `encoder=steam` create a `pyotp.contrib.Steam` instance. The release notes also mention test and documentation improvements, and the diff shows corresponding CI and documentation build changes.
Featuresv2.8.0
Release v2.8.0 updates PyOTP with constant-time OTP generation, plus documentation and CI/runtime support changes. It also drops Python 3.6 support, adds Python 3.11 testing, and updates the Sphinx configuration.
Securityv2.7.0
v2.7.0 adds Steam TOTP support. It also includes various build, test, and documentation/CI adjustments around packaging, linting, formatting, and the test runner.
Featuresv2.6.0
v2.6.0 increases the default and minimum generated secret lengths (base32 to 32 chars, hex to 40 chars) in line with RFC guidance. It also fixes a bug where calling verify() could cause subsequent provisioning_uri() calls to produce invalid results.
Breakingv2.5.1
Release v2.5.1 updates PyOTP so that parse_uri no longer rejects an optional image query parameter. The code change is narrowly scoped to parameter validation, and the tests were adjusted accordingly.
v2.5.0
PyOTP v2.5.0 adds support for embedding a logo image in the OTP provisioning URI and extends OTP parsing to allow 7-digit codes. It also increases the default and minimum generated base32 secret length to 26 for stronger default secret material.
BreakingSecurityFeaturesv2.4.1
v2.4.1 contains a fix to how otpauth URIs are parsed for period and counter, plus an enhancement to support timezone-aware datetimes in TOTP.timecode(). The diff also shows behavioral changes around HOTP counter handling that are not explicitly called out in the release notes.
Featuresv2.4.0
Release v2.4.0 adds secret generation and provisioning URI support, including a new random_hex helper and parse_uri for otpauth URIs. It also fixes data typing around TOTP.at(for_time) and adds stricter validation for secrets that are too short. The code changes include additional refactors around typing and compatibility, beyond what the release notes explicitly describe.
BreakingFeaturesv2.3.0
Release v2.3.0 primarily addresses Python 2.7 comparison behavior. The code change ensures string normalization comparisons use UTF-8 byte encoding explicitly.
v2.2.9
v2.2.9 makes a small but security-relevant change to how PyOTP compares normalized Unicode strings, and updates project metadata and CI configuration. It also includes build and release automation changes (CI adds Python 3.7, packaging version/classifiers updated, release scripts adjusted).
Features