Authentication Client for Questra to use in all other Questra Client Libraries
Project description
Questra Authentication
A Python OAuth2 authentication client for the Questra API with support for both service account and interactive user authentication flows.
Features
- Multiple Authentication Modes
- Service Account authentication (username/password)
- Interactive User authentication (OAuth2 Device Code Flow)
- Automatic Token Management
- Automatic token refresh when expired
- Configurable minimum token lifetime
- OIDC Discovery
- Automatic discovery of OAuth2 endpoints
- Support for multiple discovery paths
- Fallback to
.well-known/openid-configuration
- Type-Safe Configuration
- Dataclass-based configuration objects
- Comprehensive exception hierarchy
- Flexible Architecture
- Strategy pattern for credential handling
- Clean separation of concerns
Installation
Using pip
pip install seven2one-questra-authentication
Using poetry
poetry add seven2one-questra-authentication
Requirements
- Python >= 3.10
- requests-oauthlib >= 2.0.0
Quick Start
Service Account Authentication
from seven2one.questra.authentication import QuestraAuthentication
# Initialize client with service account credentials
client = QuestraAuthentication(
url="https://authentik.dev.example.com",
username="ServiceUser",
password="secret_password",
oidc_discovery_paths=['/application/o/questra']
)
# Get access token (automatically refreshed when expired)
access_token = client.get_access_token()
# Use token for API requests
headers = {"Authorization": f"Bearer {access_token}"}
Interactive User Authentication
from seven2one.questra.authentication import QuestraAuthentication
# Initialize client for interactive authentication
client = QuestraAuthentication(
url="https://authentik.dev.example.com",
interactive=True,
oidc_discovery_paths=['/application/o/questra']
)
# User will be prompted to authorize via browser
# Token is automatically managed after authorization
access_token = client.get_access_token()
Advanced Usage
Multiple Discovery Paths
client = QuestraAuthentication(
url="https://authentik.dev.example.com",
username="ServiceUser",
password="secret_password",
oidc_discovery_paths=[
'/application/o/techstack',
'/application/o/questra'
]
)
Multiple Base URLs
client = QuestraAuthentication(
url=[
"https://auth1.example.com",
"https://auth2.example.com"
],
username="ServiceUser",
password="secret_password",
oidc_discovery_paths=['/application/o/questra']
)
Custom Scopes
client = QuestraAuthentication(
url="https://authentik.dev.example.com",
username="ServiceUser",
password="secret_password",
scope="openid profile email"
)
Using Lower-Level API
from seven2one.questra.authentication import (
OAuth2Authentication,
OAuth2ServiceCredential,
OidcDiscoveryClient
)
# Discover OIDC configuration
discovery_client = OidcDiscoveryClient(
"https://authentik.dev.example.com/application/o/questra"
)
oidc_config = discovery_client.discover()
# Create credentials
credentials = OAuth2ServiceCredential(
username="ServiceUser",
password="secret_password"
)
# Initialize OAuth2 client
oauth_client = OAuth2Authentication(
client_id="Questra",
credentials=credentials,
oidc_config=oidc_config
)
# Authenticate
oauth_client.authenticate()
# Get access token
token = oauth_client.get_access_token()
API Reference
QuestraAuthentication
Main client class for simplified Questra API access.
QuestraAuthentication Constructor Parameters
url(str | List[str]): Base URL(s) of the identity providerclient_id(str, optional): OAuth2 client ID (default: "Questra")username(str, optional): Username for service account authenticationpassword(str, optional): Password for service account authenticationinteractive(bool, optional): Enable interactive device code flow (default: False)scope(str, optional): OAuth2 scopesoidc_discovery_paths(List[str], optional): Discovery paths (default: ['/application/o/questra'])
QuestraAuthentication Methods
get_access_token() -> str: Returns a valid access token, automatically refreshing if neededget_oidc_config() -> OidcConfig: Returns the OIDC configurationis_authenticated() -> bool: Check if client is authenticatedreauthenticate() -> None: Force re-authentication
OAuth2Authentication
Low-level OAuth2 authentication client.
OAuth2Authentication Constructor Parameters
client_id(str): OAuth2 client IDcredentials(OAuth2Credential): Credential strategyoidcConfig(OidcConfig): OIDC configurationscope(str, optional): OAuth2 scopesminimum_token_lifetime_seconds(int, optional): Minimum lifetime before refresh (default: 60)
OAuth2Authentication Methods
authenticate() -> None: Perform initial authenticationget_access_token() -> str: Get valid access token
Credential Types
OAuth2ServiceCredential
Service account credentials using username/password.
credentials = OAuth2ServiceCredential(
username="ServiceUser",
password="secret_password"
)
OAuth2InteractiveUserCredential
Interactive user credentials using device code flow.
credentials = OAuth2InteractiveUserCredential()
OidcConfig
Immutable dataclass containing OIDC endpoints.
OidcConfig Attributes
issuer: Issuer URLauthorization_endpoint: Authorization endpoint URLtoken_endpoint: Token endpoint URLuserinfo_endpoint: User info endpoint URLend_session_endpoint: End session endpoint URLdevice_authorization_endpoint: Device authorization endpoint URL
OidcConfig Methods
to_dict() -> Dict[str, str]: Convert to dictionaryto_json() -> str: Convert to JSON string
Exception Hierarchy
QuestraAuthenticationError
\x00\x00 AuthenticationError
\x00\x00 NotAuthenticatedError
\x00\x00 SessionNotInitializedError
\x00\x00 InvalidCredentialsError
\x00\x00 TokenExpiredError
\x00\x00 OidcDiscoveryError
Exception Descriptions
QuestraAuthenticationError: Base exception for all client errorsAuthenticationError: General authentication failureNotAuthenticatedError: Operation requires authentication but client is not authenticatedSessionNotInitializedError: OAuth2 session not initializedInvalidCredentialsError: Invalid or wrong credential type providedTokenExpiredError: Token expired and cannot be refreshedOidcDiscoveryError: OIDC discovery failed (includes URLs tried and original error)
Error Handling
from seven2one.questra.authentication import (
QuestraAuthentication,
AuthenticationError,
OidcDiscoveryError
)
try:
client = QuestraAuthentication(
url="https://authentik.dev.example.com",
username="ServiceUser",
password="wrong_password"
)
except OidcDiscoveryError as e:
print(f"OIDC discovery failed: {e}")
print(f"Tried URLs: {e.urls}")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
# Get token with error handling
try:
token = client.get_access_token()
except NotAuthenticatedError:
print("Not authenticated. Please authenticate first.")
client.reauthenticate()
Development
Setup Development Environment
# Clone repository
git clone <repository-url>
cd S2O.Questra.Python.Authentication
# Install dependencies
poetry install
# Install development and test dependencies
poetry install --with dev,test
# Install pre-commit hooks
poetry run pre-commit install
Code Quality Tools
This project uses multiple tools to ensure code quality, consistency, and type safety:
Ruff - Fast Linter & Formatter
Ruff combines linting and formatting in a single, extremely fast tool.
# Run linter with auto-fixes
poetry run ruff check . --fix
# Check code formatting
poetry run ruff format --check .
# Format code
poetry run ruff format .
mypy - Static Type Checker
mypy validates type hints and catches type-related bugs before runtime.
# Run mypy on source code
poetry run mypy src/
# Run with verbose output
poetry run mypy src/ --verbose
Pyright - Advanced Type Checker
Pyright provides additional type checking with strict mode enabled.
# Run Pyright on source code
poetry run pyright src/
# Check specific file
poetry run pyright src/questra_authentication/authentication.py
Pre-commit Hooks
All quality checks run automatically on git commit:
# Run all pre-commit hooks manually
poetry run pre-commit run --all-files
# Update hook versions
poetry run pre-commit autoupdate
VS Code Integration
The project includes VS Code settings (.vscode/settings.json) that:
- Automatically format on save with Ruff
- Run linters on file changes
- Display type hints inline
- Organize imports automatically
Recommended extensions are listed in .vscode/extensions.json.
Running Tests
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=questra_authentication
# Run specific test file
poetry run pytest tests/test_authentication.py
CI/CD Pipeline
The project uses Azure DevOps for continuous integration. The pipeline (azure-pipelines.yml) automatically runs:
-
Code Quality Checks
- Ruff linting
- Ruff formatting validation
-
Type Checking
- mypy validation
- Pyright validation
-
Tests
- Pytest execution
All checks must pass before code can be merged.
Project Structure
S2O.Questra.Python.Authentication/
📁 src/
📁 questra_authentication/
- __init__.py
- authentication.py # OAuth2 authentication logic
- device_client.py # Device code flow implementation
- exceptions.py # Custom exception classes
- questra_authentication.py # Main client interface
📁 tests/
- conftest.py
- test_authentication.py
- test_oidc_discovery.py
- test_questra_authentication.py
- pyproject.toml
- README.md
License
[Add your license information here]
Contributing
[Add contributing guidelines here]
Authors
- Jürgen Talasch (juergen.talasch@seven2one.de)
Changelog
Version 0.1.4
- Current release
- OAuth2 authentication with service account and interactive flows
- Automatic token refresh
- OIDC discovery with fallback support
Project details
Release history Release notifications | RSS feed
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 seven2one_questra_authentication-0.3.0.tar.gz.
File metadata
- Download URL: seven2one_questra_authentication-0.3.0.tar.gz
- Upload date:
- Size: 14.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bbf8d6fa902771c9570542a8a9037958879717a80d90d20a465835231f532b27
|
|
| MD5 |
27bfe9dcc303cc84802fc608c25b9f22
|
|
| BLAKE2b-256 |
e8d019e203535f857a59468a16192f17accd5595bcb2104aad345e255ff6874e
|
File details
Details for the file seven2one_questra_authentication-0.3.0-py3-none-any.whl.
File metadata
- Download URL: seven2one_questra_authentication-0.3.0-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.11 {"installer":{"name":"uv","version":"0.9.11"},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9125f64279866def4fd39fe725f708dd6e4f3dd89a28b0a558e3a67dc72102d
|
|
| MD5 |
b99e7d2c0be638c4f1149ef522beac31
|
|
| BLAKE2b-256 |
9c2419fd9355184b8e23ba64f0b877a96061b769d1166b96fe7bd16fa2aab4c1
|