LionAuth
A reusable Python library for implementing Time-based One-Time Password (TOTP) authentication.
LionAuth provides the core functionality required to integrate authenticator-app-based authentication into Python applications.
It is designed to work with compatible authenticator applications such as Google Authenticator and Microsoft Authenticator.
Features
- TOTP secret generation
- OTP generation
- OTP verification
- Configurable OTP digit length
- Configurable OTP time interval
- SHA1, SHA256, and SHA512 support
- Standard
otpauth://provisioning URI generation - Input validation
- Custom authentication exceptions
- Configurable verification window
- No database required
- No QR-code dependency
- Framework independent
Requirements
- Python 3.10 or higher
- PyOTP 2.9 or higher
Installation
Install LionAuth using pip:
pip install lionauth
Quick Start
from lionauth import TOTPAuthenticator
# Create the authenticator
auth = TOTPAuthenticator()
# Generate a TOTP secret
secret = auth.generate_secret()
print("Secret:", secret)
# Generate a provisioning URI
uri = auth.get_provisioning_uri(
secret=secret,
account_name="user@example.com",
)
print("Provisioning URI:", uri)
# Generate the current OTP
otp = auth.generate_otp(secret)
print("OTP:", otp)
# Verify the OTP
result = auth.verify(
secret=secret,
otp=otp,
)
print("Verified:", result)
Example output:
Secret: JBSWY3DPEHPK3PXP
Provisioning URI: otpauth://totp/...
OTP: 123456
Verified: True
How LionAuth Works
LionAuth implements Time-based One-Time Password (TOTP) authentication.
A TOTP system uses a shared secret between an application and an authenticator application. Both sides use the secret and the current time to generate the same temporary one-time password.
The basic process is:
LionAuth
|
|
Generate Secret
|
v
TOTP Secret
|
+---------+---------+
| |
v v
Authenticator App Application
| |
| |
Generates OTP Stores Secret
| |
+---------+---------+
|
v
User enters OTP
|
v
LionAuth.verify()
|
+------+------+
| |
Valid Invalid
| |
v v
True InvalidOTPError
The application integrating LionAuth is responsible for managing users and securely storing their TOTP secrets.
Generating a Secret
Generate a new TOTP secret using:
from lionauth import TOTPAuthenticator
auth = TOTPAuthenticator()
secret = auth.generate_secret()
print(secret)
The generated secret is a sensitive authentication credential.
Applications should:
- Store it securely.
- Protect it from unauthorized access.
- Never expose it unnecessarily.
- Never commit it to source control.
- Avoid logging it.
Provisioning URI
LionAuth can generate a standard otpauth:// provisioning URI.
uri = auth.get_provisioning_uri(
secret=secret,
account_name="user@example.com",
)
print(uri)
Example:
otpauth://totp/LionAuth:user%40example.com?secret=XXXXXXXX&issuer=LionAuth&algorithm=SHA1&digits=6&period=30
The URI contains the information required by compatible authenticator applications to configure the TOTP account.
LionAuth intentionally does not generate QR codes.
This keeps the library lightweight and allows the application integrating LionAuth to decide how the provisioning URI should be presented to the user.
For example, an application may choose to:
- Display the URI directly.
- Generate its own QR code.
- Provide the URI through another secure provisioning mechanism.
Generating an OTP
Generate the current OTP using:
otp = auth.generate_otp(secret)
print(otp)
Example:
483921
The OTP changes according to the configured time interval.
Verifying an OTP
Verify an OTP using:
result = auth.verify(
secret=secret,
otp=otp,
)
print(result)
A valid OTP returns:
True
An invalid OTP raises:
InvalidOTPError
Example:
from lionauth import (
TOTPAuthenticator,
InvalidOTPError,
)
auth = TOTPAuthenticator()
secret = auth.generate_secret()
otp = auth.generate_otp(secret)
try:
auth.verify(secret, otp)
print("Authentication successful")
except InvalidOTPError:
print("Invalid authentication code")
Configuration
LionAuth provides TOTPConfig for customizing TOTP behavior.
from lionauth import (
TOTPAuthenticator,
TOTPConfig,
)
config = TOTPConfig(
digits=6,
interval=30,
algorithm="SHA1",
issuer="My Application",
valid_window=0,
)
auth = TOTPAuthenticator(config)
Configuration Options
| Option | Default | Description |
|---|---|---|
digits |
6 |
Number of digits in the generated OTP |
interval |
30 |
Number of seconds before the OTP changes |
algorithm |
SHA1 |
Hashing algorithm |
issuer |
LionAuth |
Application/service name |
valid_window |
0 |
Number of adjacent time windows accepted during verification |
Supported algorithms
SHA1
SHA256
SHA512
Supported OTP digit lengths
6
8
Custom Configuration Example
from lionauth import (
TOTPAuthenticator,
TOTPConfig,
)
config = TOTPConfig(
digits=8,
interval=60,
algorithm="SHA256",
issuer="My Application",
valid_window=1,
)
auth = TOTPAuthenticator(config)
secret = auth.generate_secret()
otp = auth.generate_otp(secret)
print("OTP:", otp)
print("Verified:", auth.verify(secret, otp))
Enrollment Workflow
A typical authenticator enrollment process looks like this:
1. User chooses to enable authenticator authentication
|
v
2. Application requests a secret from LionAuth
|
v
3. LionAuth generates the secret
|
v
4. Application securely stores the secret
|
v
5. Application requests a provisioning URI
|
v
6. User configures their authenticator app
|
v
7. Authenticator app generates an OTP
|
v
8. User enters the OTP
|
v
9. Application calls LionAuth.verify()
|
+------+------+
| |
Valid Invalid
| |
v v
Enable TOTP Reject OTP
The application should not mark TOTP as enabled merely because a secret was generated.
The user should first prove that their authenticator application is correctly configured by successfully providing a valid OTP.
A recommended enrollment state is:
Secret generated
|
v
Pending enrollment
|
v
User provides OTP
|
v
OTP verified
|
v
TOTP enabled
Authentication Workflow
After enrollment, authentication works like this:
User
|
| Login
v
Application
|
| Request OTP
v
Authenticator App
|
| Generate current OTP
v
User
|
| Enter OTP
v
Application
|
| secret + OTP
v
LionAuth
|
| verify()
|
+------------+
| |
v v
Valid Invalid
| |
v v
True Error
|
v
Application grants access
LionAuth verifies the OTP. The application remains responsible for deciding what happens after successful verification, such as creating a session or issuing a JWT.
Exceptions
LionAuth provides its own exception hierarchy.
from lionauth import (
LionAuthError,
ConfigurationError,
InvalidSecretError,
InvalidOTPError,
InvalidInputError,
)
Exception Hierarchy
LionAuthError
|
+-- ConfigurationError
|
+-- InvalidSecretError
|
+-- InvalidOTPError
|
+-- InvalidInputError
LionAuthError
LionAuthError is the base exception for LionAuth errors.
You can catch all LionAuth-specific errors using:
from lionauth import LionAuthError
try:
auth.verify(secret, otp)
except LionAuthError:
print("A LionAuth error occurred")
ConfigurationError
Raised when the TOTP configuration is invalid.
Example:
from lionauth import (
TOTPConfig,
ConfigurationError,
)
try:
config = TOTPConfig(
digits=7,
)
except ConfigurationError as error:
print(error)
InvalidSecretError
Raised when an invalid TOTP secret is supplied.
Example:
from lionauth import InvalidSecretError
try:
auth.generate_otp("")
except InvalidSecretError as error:
print(error)
InvalidOTPError
Raised when an OTP is invalid.
Example:
from lionauth import InvalidOTPError
try:
auth.verify(
secret=secret,
otp="123456",
)
except InvalidOTPError:
print("Invalid OTP")
InvalidInputError
Raised when an input does not meet the expected requirements.
Example:
from lionauth import InvalidInputError
try:
auth.get_provisioning_uri(
secret=secret,
account_name="",
)
except InvalidInputError as error:
print(error)
What LionAuth Does Not Handle
LionAuth is intentionally focused on TOTP authentication.
It does not manage:
- User accounts
- User registration
- Password authentication
- Password storage
- Databases
- JWT authentication
- Sessions
- Email delivery
- SMS OTP
- QR-code generation
- User permissions
- Roles
- Application-specific authorization
These responsibilities belong to the application integrating LionAuth.
This separation allows LionAuth to remain lightweight and framework independent.
Database
LionAuth does not require a database.
The application using LionAuth is responsible for storing the user's TOTP secret.
For example, an application might have a user record containing:
users
--------------------------------
id
email
name
totp_secret
totp_enabled
The exact database structure is left to the application.
The relationship is:
Application Database
|
| TOTP secret
v
LionAuth
|
+-- Generate OTP
|
+-- Verify OTP
|
+-- Generate provisioning URI
LionAuth itself does not store users or TOTP secrets in a database.
Security Considerations
TOTP secrets are sensitive authentication credentials.
Applications using LionAuth should:
- Store TOTP secrets securely.
- Protect secrets from unauthorized access.
- Never expose TOTP secrets in logs.
- Never expose secrets to clients unnecessarily.
- Protect secrets at rest using appropriate application and database security controls.
- Require successful OTP verification before completing enrollment.
- Use a reasonable
valid_window. - Protect authentication endpoints against brute-force attempts.
- Apply appropriate rate limiting to OTP verification endpoints.
- Avoid storing OTPs permanently.
- Never commit TOTP secrets to source control.
- Avoid returning TOTP secrets in API responses unless absolutely necessary.
Important
A TOTP secret should be treated like a password.
Anyone who obtains the secret can generate valid OTPs for that account.
LionAuth provides the TOTP functionality, but the application integrating LionAuth is responsible for protecting the secret and the authentication endpoint.
Development
Clone the project:
git clone <repository-url>
Enter the project directory:
cd LionAuth
Create a virtual environment:
python -m venv venv
Activate the virtual environment.
Linux/macOS
source venv/bin/activate
Windows
venv\Scripts\activate
Install LionAuth with development dependencies:
pip install -e ".[dev]"
Running Tests
LionAuth uses pytest for automated testing.
Run the complete test suite:
pytest
A successful test run should look similar to:
======================== test session starts ========================
tests/test_config.py ........
tests/test_totp.py .........
========================= XX passed =========================
The exact number of tests may change as the project evolves.
Building the Package
Install the Python build tool:
pip install build
Build LionAuth:
python -m build
The distribution files will be generated inside:
dist/
Example:
dist/
├── lionauth-0.1.0-py3-none-any.whl
└── lionauth-0.1.0.tar.gz
The .whl file is the wheel distribution and the .tar.gz file is the source distribution.
Testing the Built Package
You can test the built package in a clean virtual environment.
Create a separate environment:
python -m venv test-env
Activate it:
Linux/macOS
source test-env/bin/activate
Windows
test-env\Scripts\activate
Install the built wheel:
pip install dist/lionauth-0.1.0-py3-none-any.whl
Then test:
from lionauth import TOTPAuthenticator
auth = TOTPAuthenticator()
secret = auth.generate_secret()
otp = auth.generate_otp(secret)
print(auth.verify(secret, otp))
Expected output:
True
Project Structure
LionAuth/
|
+-- src/
| |
| +-- lionauth/
| |
| +-- __init__.py
| +-- config.py
| +-- exceptions.py
| +-- totp.py
|
+-- tests/
| |
| +-- test_config.py
| +-- test_totp.py
|
+-- pyproject.toml
+-- README.md
Design Philosophy
LionAuth follows a simple principle:
LionAuth handles TOTP. The application handles everything else.
This keeps the library:
- Lightweight
- Framework independent
- Database independent
- Easy to integrate
- Easy to test
- Reusable across Python applications
LionAuth can be integrated into applications built with:
- Django
- FastAPI
- Flask
- Other Python web frameworks
- CLI applications
- Custom Python applications
Complete Example
from lionauth import (
TOTPAuthenticator,
InvalidOTPError,
)
# Create the authenticator
auth = TOTPAuthenticator()
# Generate a secret during enrollment
secret = auth.generate_secret()
print("Secret:", secret)
# Generate a provisioning URI
uri = auth.get_provisioning_uri(
secret=secret,
account_name="user@example.com",
)
print("Provisioning URI:", uri)
# The user configures their authenticator application
# and obtains an OTP.
# Generate the current OTP for demonstration purposes
otp = auth.generate_otp(secret)
print("Current OTP:", otp)
# Verify the OTP
try:
if auth.verify(
secret=secret,
otp=otp,
):
print("Authentication successful")
except InvalidOTPError:
print("Authentication failed")
API Overview
| Method | Description |
|---|---|
generate_secret() |
Generates a new TOTP secret |
generate_otp(secret) |
Generates the current OTP |
verify(secret, otp) |
Verifies an OTP |
get_provisioning_uri(secret, account_name) |
Generates an otpauth:// provisioning URI |
Example Integration
LionAuth can be used as the TOTP layer inside a larger authentication system.
For example:
Your Application
|
+--------------+--------------+
| |
v v
User Management Authentication
| |
| +-----+-----+
| | |
| Login TOTP
| |
| v
| LionAuth
| |
| OTP verify
| |
+---------------+-------------------+
|
v
Authorization
The application can use its existing authentication system while delegating TOTP operations to LionAuth.
Version
Current version:
0.1.0
License
MIT
Author
LionAuth is a reusable TOTP authentication library for Python applications.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file lionauth-0.1.0.tar.gz.
File metadata
- Download URL: lionauth-0.1.0.tar.gz
- Upload date:
- Size: 14.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b3187a64999e0f3e346127f0965f4cb3ac9887a410c6bab2a99a6e8dfbb0764
|
|
| MD5 |
5cb5c1d7f1f0238d2bdf2ed3edd1c932
|
|
| BLAKE2b-256 |
bd3a76be7ab8590a8a51a578fa12eadfa60afb11c0b68b0e461d35a68705e88a
|
File details
Details for the file lionauth-0.1.0-py3-none-any.whl.
File metadata
- Download URL: lionauth-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ebffd577fb197f3db5ce62afbf8cb4ff5bb923b7778f036b657aa8661416709
|
|
| MD5 |
2d5ce9ede1c2eaa7bdeb2294bc5cfde5
|
|
| BLAKE2b-256 |
395922c914fdf28face55ea41072545f9f71111a1716414bd789a346ad6e45ae
|