pico-server-auth 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pico_server_auth-0.1.0/.coveragerc +7 -0
- pico_server_auth-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +24 -0
- pico_server_auth-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +15 -0
- pico_server_auth-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- pico_server_auth-0.1.0/.github/dependabot.yml +10 -0
- pico_server_auth-0.1.0/.github/workflows/ci.yml +67 -0
- pico_server_auth-0.1.0/.github/workflows/codeql.yml +21 -0
- pico_server_auth-0.1.0/.github/workflows/docs.yml +48 -0
- pico_server_auth-0.1.0/.github/workflows/publish-to-pypi.yml +24 -0
- pico_server_auth-0.1.0/AGENTS.md +56 -0
- pico_server_auth-0.1.0/CHANGELOG.md +21 -0
- pico_server_auth-0.1.0/CLAUDE.md +34 -0
- pico_server_auth-0.1.0/CODE_OF_CONDUCT.md +35 -0
- pico_server_auth-0.1.0/CONTRIBUTING.md +37 -0
- pico_server_auth-0.1.0/LICENSE +21 -0
- pico_server_auth-0.1.0/MANIFEST.in +5 -0
- pico_server_auth-0.1.0/PKG-INFO +169 -0
- pico_server_auth-0.1.0/README.md +129 -0
- pico_server_auth-0.1.0/SECURITY.md +11 -0
- pico_server_auth-0.1.0/docs/architecture.md +133 -0
- pico_server_auth-0.1.0/docs/faq.md +62 -0
- pico_server_auth-0.1.0/docs/getting-started.md +101 -0
- pico_server_auth-0.1.0/docs/hooks.py +7 -0
- pico_server_auth-0.1.0/docs/how-to/custom-challenge-store.md +121 -0
- pico_server_auth-0.1.0/docs/how-to/embed-in-app.md +90 -0
- pico_server_auth-0.1.0/docs/how-to/index.md +10 -0
- pico_server_auth-0.1.0/docs/how-to/standalone.md +85 -0
- pico_server_auth-0.1.0/docs/how-to/testing.md +190 -0
- pico_server_auth-0.1.0/docs/index.md +65 -0
- pico_server_auth-0.1.0/docs/javascripts/extra.js +10 -0
- pico_server_auth-0.1.0/docs/reference/config.md +73 -0
- pico_server_auth-0.1.0/docs/reference/endpoints.md +191 -0
- pico_server_auth-0.1.0/docs/reference/index.md +20 -0
- pico_server_auth-0.1.0/docs/requirements.txt +7 -0
- pico_server_auth-0.1.0/docs/skills.md +15 -0
- pico_server_auth-0.1.0/docs/stylesheets/extra.css +52 -0
- pico_server_auth-0.1.0/docs/troubleshooting.md +55 -0
- pico_server_auth-0.1.0/docs/user-guide/index.md +33 -0
- pico_server_auth-0.1.0/docs/user-guide/jwks.md +91 -0
- pico_server_auth-0.1.0/docs/user-guide/password-auth.md +70 -0
- pico_server_auth-0.1.0/docs/user-guide/wallet-auth.md +194 -0
- pico_server_auth-0.1.0/examples/embedded_app.py +49 -0
- pico_server_auth-0.1.0/examples/standalone_auth.py +33 -0
- pico_server_auth-0.1.0/examples/wallet_login.py +54 -0
- pico_server_auth-0.1.0/mkdocs.yml +158 -0
- pico_server_auth-0.1.0/pyproject.toml +95 -0
- pico_server_auth-0.1.0/setup.cfg +4 -0
- pico_server_auth-0.1.0/src/pico_server_auth/__init__.py +15 -0
- pico_server_auth-0.1.0/src/pico_server_auth/_version.py +1 -0
- pico_server_auth-0.1.0/src/pico_server_auth/challenge_store.py +57 -0
- pico_server_auth-0.1.0/src/pico_server_auth/config.py +24 -0
- pico_server_auth-0.1.0/src/pico_server_auth/controllers.py +129 -0
- pico_server_auth-0.1.0/src/pico_server_auth/py.typed +0 -0
- pico_server_auth-0.1.0/src/pico_server_auth/token_issuer.py +100 -0
- pico_server_auth-0.1.0/src/pico_server_auth/wallet_verifier.py +81 -0
- pico_server_auth-0.1.0/src/pico_server_auth.egg-info/PKG-INFO +169 -0
- pico_server_auth-0.1.0/src/pico_server_auth.egg-info/SOURCES.txt +67 -0
- pico_server_auth-0.1.0/src/pico_server_auth.egg-info/dependency_links.txt +1 -0
- pico_server_auth-0.1.0/src/pico_server_auth.egg-info/entry_points.txt +2 -0
- pico_server_auth-0.1.0/src/pico_server_auth.egg-info/requires.txt +13 -0
- pico_server_auth-0.1.0/src/pico_server_auth.egg-info/top_level.txt +1 -0
- pico_server_auth-0.1.0/test/Dockerfile.dev +26 -0
- pico_server_auth-0.1.0/tests/__init__.py +0 -0
- pico_server_auth-0.1.0/tests/conftest.py +21 -0
- pico_server_auth-0.1.0/tests/test_challenge_store.py +64 -0
- pico_server_auth-0.1.0/tests/test_controllers.py +213 -0
- pico_server_auth-0.1.0/tests/test_token_issuer.py +81 -0
- pico_server_auth-0.1.0/tests/test_wallet_verifier.py +60 -0
- pico_server_auth-0.1.0/tox.ini +21 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: Report a bug
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: description
|
|
7
|
+
attributes: { label: Description }
|
|
8
|
+
validations: { required: true }
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: steps
|
|
11
|
+
attributes: { label: Steps to Reproduce, render: python }
|
|
12
|
+
validations: { required: true }
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: expected
|
|
15
|
+
attributes: { label: Expected Behavior }
|
|
16
|
+
validations: { required: true }
|
|
17
|
+
- type: input
|
|
18
|
+
id: version
|
|
19
|
+
attributes: { label: Package Version }
|
|
20
|
+
validations: { required: true }
|
|
21
|
+
- type: input
|
|
22
|
+
id: python
|
|
23
|
+
attributes: { label: Python Version }
|
|
24
|
+
validations: { required: true }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: Feature Request
|
|
2
|
+
description: Suggest an improvement
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes: { label: Problem }
|
|
8
|
+
validations: { required: true }
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: solution
|
|
11
|
+
attributes: { label: Proposed Solution }
|
|
12
|
+
validations: { required: true }
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: alternatives
|
|
15
|
+
attributes: { label: Alternatives Considered }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
## Changes
|
|
4
|
+
|
|
5
|
+
-
|
|
6
|
+
|
|
7
|
+
## Checklist
|
|
8
|
+
|
|
9
|
+
- [ ] Tests pass (`pytest tests/ -v`)
|
|
10
|
+
- [ ] Linting passes (`ruff check src/ tests/`)
|
|
11
|
+
- [ ] CHANGELOG.md updated (if user-facing)
|
|
12
|
+
- [ ] No new runtime dependencies
|
|
13
|
+
- [ ] Single-line commit messages
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
lint:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.11"
|
|
16
|
+
- run: pip install ruff
|
|
17
|
+
- run: ruff check src/ tests/
|
|
18
|
+
- run: ruff format --check src/ tests/
|
|
19
|
+
|
|
20
|
+
tests:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
strategy:
|
|
23
|
+
matrix:
|
|
24
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
with:
|
|
28
|
+
fetch-depth: 0
|
|
29
|
+
- uses: actions/setup-python@v5
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
- run: pip install tox
|
|
33
|
+
- name: Run tests with coverage
|
|
34
|
+
env:
|
|
35
|
+
SETUPTOOLS_SCM_PRETEND_VERSION: "0.1.0"
|
|
36
|
+
run: |
|
|
37
|
+
tox -e cov
|
|
38
|
+
mv .coverage .coverage.${{ matrix.python-version }}
|
|
39
|
+
- uses: actions/upload-artifact@v4
|
|
40
|
+
with:
|
|
41
|
+
name: coverage-${{ matrix.python-version }}
|
|
42
|
+
path: .coverage.${{ matrix.python-version }}
|
|
43
|
+
include-hidden-files: true
|
|
44
|
+
if-no-files-found: error
|
|
45
|
+
|
|
46
|
+
coverage:
|
|
47
|
+
needs: tests
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@v4
|
|
51
|
+
- uses: actions/setup-python@v5
|
|
52
|
+
with:
|
|
53
|
+
python-version: "3.12"
|
|
54
|
+
- uses: actions/download-artifact@v4
|
|
55
|
+
with:
|
|
56
|
+
path: coverage-reports
|
|
57
|
+
- name: Combine and upload
|
|
58
|
+
run: |
|
|
59
|
+
pip install coverage
|
|
60
|
+
files=$(find coverage-reports -type f -name ".coverage.*")
|
|
61
|
+
if [ -z "$files" ]; then echo "No coverage files"; exit 1; fi
|
|
62
|
+
coverage combine $files
|
|
63
|
+
coverage xml
|
|
64
|
+
- uses: codecov/codecov-action@v4
|
|
65
|
+
with:
|
|
66
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
67
|
+
files: coverage.xml
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
branches: [main]
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: "0 6 * * 1"
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
security-events: write
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
analyze:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: github/codeql-action/init@v3
|
|
20
|
+
with: { languages: python }
|
|
21
|
+
- uses: github/codeql-action/analyze@v3
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
paths: [docs/**, mkdocs.yml]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
paths: [docs/**, mkdocs.yml]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
pages: write
|
|
14
|
+
id-token: write
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: pages
|
|
18
|
+
cancel-in-progress: false
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
validate:
|
|
22
|
+
if: github.event_name == 'pull_request'
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
with: { fetch-depth: 0 }
|
|
27
|
+
- uses: actions/setup-python@v5
|
|
28
|
+
with: { python-version: "3.12" }
|
|
29
|
+
- run: pip install -r docs/requirements.txt
|
|
30
|
+
- run: mkdocs build --strict
|
|
31
|
+
|
|
32
|
+
deploy:
|
|
33
|
+
if: github.event_name != 'pull_request'
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
environment:
|
|
36
|
+
name: github-pages
|
|
37
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
with: { fetch-depth: 0 }
|
|
41
|
+
- uses: actions/setup-python@v5
|
|
42
|
+
with: { python-version: "3.12" }
|
|
43
|
+
- run: pip install -r docs/requirements.txt
|
|
44
|
+
- run: mkdocs build --strict --verbose
|
|
45
|
+
- uses: actions/upload-pages-artifact@v3
|
|
46
|
+
with: { path: site }
|
|
47
|
+
- id: deployment
|
|
48
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
id-token: write
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
with: { fetch-depth: 0 }
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with: { python-version: "3.x" }
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
21
|
+
with:
|
|
22
|
+
skip-existing: true
|
|
23
|
+
verify-metadata: true
|
|
24
|
+
attestations: true
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# pico-server-auth
|
|
2
|
+
|
|
3
|
+
Embeddable auth server module for pico-boot. JWT issuance, wallet challenge/verify login, password login, and JWKS endpoint as FastAPI controllers.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e ".[test]" # Install in dev mode
|
|
9
|
+
pytest tests/ -v # Run tests
|
|
10
|
+
pytest --cov=pico_server_auth --cov-report=term-missing tests/ # Coverage
|
|
11
|
+
tox # Full matrix (3.11-3.14)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Project Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
src/pico_server_auth/
|
|
18
|
+
__init__.py # Public API exports (ChallengeStore, InMemoryChallengeStore, ServerAuthSettings, TokenIssuer, WalletVerifier)
|
|
19
|
+
config.py # ServerAuthSettings (@configured, prefix="server_auth", mapping="tree")
|
|
20
|
+
controllers.py # AuthController (@controller, prefix="/auth") — jwks, challenge, wallet_login, password_login
|
|
21
|
+
challenge_store.py # ChallengeStore protocol + InMemoryChallengeStore (@component)
|
|
22
|
+
wallet_verifier.py # WalletVerifier (@component) — ML-DSA-65, Ed25519, secp256k1
|
|
23
|
+
token_issuer.py # TokenIssuer (@component) — RS256 JWT signing + JWKS export
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Key Concepts
|
|
27
|
+
|
|
28
|
+
- **`AuthController`**: FastAPI controller with `prefix="/auth"`. All endpoints are `@allow_anonymous` (public auth API).
|
|
29
|
+
- **`ServerAuthSettings`**: Configured via `@configured(prefix="server_auth")`. Fields: issuer, audience, algorithm, access_token_expire_minutes, refresh_token_expire_days, challenge_ttl_seconds, auto_create_admin, admin_email, admin_password, supported_wallet_algorithms.
|
|
30
|
+
- **`ChallengeStore`**: Protocol for challenge nonce storage. Default `InMemoryChallengeStore` uses dict with TTL. Replace with Redis/DB by registering a `@component` that implements the protocol.
|
|
31
|
+
- **`WalletVerifier`**: Verifies wallet signatures. Lazy-loads crypto backends (`cryptography` library) on first use.
|
|
32
|
+
- **`TokenIssuer`**: Generates RSA-2048 keypair at startup. Issues access tokens (configurable expiry) and refresh tokens. Exports JWKS for pico-client-auth.
|
|
33
|
+
- **Embedded mode**: pico-server-auth runs inside the same pico-boot process as your app controllers.
|
|
34
|
+
- **Standalone mode**: pico-server-auth runs as a dedicated auth service; other services fetch JWKS remotely.
|
|
35
|
+
|
|
36
|
+
## Code Style
|
|
37
|
+
|
|
38
|
+
- Python 3.11+
|
|
39
|
+
- Async endpoints in controller, sync internals for crypto operations
|
|
40
|
+
- Use pico-ioc's `@component`, `@configured` decorators
|
|
41
|
+
- Use pico-fastapi's `@controller`, `@get`, `@post` decorators
|
|
42
|
+
- Error responses: JSON `{"detail": "..."}` via FastAPI `HTTPException`
|
|
43
|
+
|
|
44
|
+
## Testing
|
|
45
|
+
|
|
46
|
+
- pytest + pytest-asyncio (mode=auto)
|
|
47
|
+
- RSA keypair fixture for token signing
|
|
48
|
+
- Mock ChallengeStore for controller tests
|
|
49
|
+
- httpx AsyncClient with ASGITransport for e2e tests
|
|
50
|
+
|
|
51
|
+
## Boundaries
|
|
52
|
+
|
|
53
|
+
- Do not modify `_version.py`
|
|
54
|
+
- Public API is defined in `__init__.py` — ChallengeStore, InMemoryChallengeStore, ServerAuthSettings, TokenIssuer, WalletVerifier
|
|
55
|
+
- No direct dependency on pico-boot (uses entry point for auto-discovery)
|
|
56
|
+
- Depends on pico-client-auth only for `@allow_anonymous` decorator
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to pico-server-auth will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-03-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `AuthController` with `/auth/jwks`, `/auth/challenge`, `/auth/wallet`, and `/auth/login` endpoints.
|
|
13
|
+
- `ServerAuthSettings` configuration with `@configured(prefix="server_auth")`.
|
|
14
|
+
- `TokenIssuer` for RS256 JWT access and refresh token issuance.
|
|
15
|
+
- `WalletVerifier` with support for ML-DSA-65, Ed25519, and secp256k1 signature verification.
|
|
16
|
+
- `ChallengeStore` protocol with `InMemoryChallengeStore` default implementation.
|
|
17
|
+
- JWKS endpoint compatible with pico-client-auth token validation.
|
|
18
|
+
- Password-based admin login with configurable credentials.
|
|
19
|
+
- Auto-discovery via `pico_boot.modules` entry point.
|
|
20
|
+
|
|
21
|
+
[0.1.0]: https://github.com/dperezcabrera/pico-server-auth/releases/tag/v0.1.0
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
Read and follow ./AGENTS.md for project conventions.
|
|
2
|
+
|
|
3
|
+
## Pico Ecosystem Context
|
|
4
|
+
|
|
5
|
+
pico-server-auth is an embeddable auth server module for pico-boot applications. It provides:
|
|
6
|
+
- JWT issuance (RS256) via `TokenIssuer`
|
|
7
|
+
- Wallet challenge/verify login (ML-DSA-65, Ed25519, secp256k1) via `WalletVerifier`
|
|
8
|
+
- Password-based admin login via `AuthController`
|
|
9
|
+
- JWKS endpoint for pico-client-auth token validation
|
|
10
|
+
- In-memory `ChallengeStore` with TTL expiry (replaceable via protocol)
|
|
11
|
+
|
|
12
|
+
It uses:
|
|
13
|
+
- `@component`, `@configured` from pico-ioc
|
|
14
|
+
- `@controller`, `@get`, `@post` from pico-fastapi
|
|
15
|
+
- `@allow_anonymous` from pico-client-auth
|
|
16
|
+
- Auto-discovered via `pico_boot.modules` entry point
|
|
17
|
+
|
|
18
|
+
## Key Components
|
|
19
|
+
|
|
20
|
+
- **`ServerAuthSettings`**: `@configured(prefix="server_auth")` — issuer, audience, algorithm, TTLs, admin credentials, supported wallet algorithms
|
|
21
|
+
- **`AuthController`**: `@controller(prefix="/auth")` — endpoints: `/auth/jwks`, `/auth/challenge`, `/auth/wallet`, `/auth/login`
|
|
22
|
+
- **`TokenIssuer`**: `@component` — RSA key generation, JWT signing, JWKS export
|
|
23
|
+
- **`WalletVerifier`**: `@component` — signature verification for ML-DSA-65, Ed25519, secp256k1
|
|
24
|
+
- **`ChallengeStore`**: Protocol with `InMemoryChallengeStore` default (`@component(on_missing_selector=ChallengeStore)`)
|
|
25
|
+
|
|
26
|
+
## Key Reminders
|
|
27
|
+
|
|
28
|
+
- **NEVER change `version_scheme`** in pyproject.toml. It MUST remain `"post-release"`.
|
|
29
|
+
- requires-python >= 3.11
|
|
30
|
+
- Commit messages: one line only
|
|
31
|
+
- Tokens issued here are compatible with pico-client-auth validation (same issuer/audience)
|
|
32
|
+
- `ChallengeStore` is a Protocol — users can replace with Redis/DB by registering their own `@component`
|
|
33
|
+
- `WalletVerifier` lazy-loads crypto backends to avoid hard dependencies
|
|
34
|
+
- `TokenIssuer` generates a fresh RSA keypair on startup (key ID: `pico-server-auth-1`)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity
|
|
10
|
+
and orientation.
|
|
11
|
+
|
|
12
|
+
## Our Standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to a positive environment:
|
|
15
|
+
|
|
16
|
+
* Using welcoming and inclusive language
|
|
17
|
+
* Being respectful of differing viewpoints and experiences
|
|
18
|
+
* Gracefully accepting constructive criticism
|
|
19
|
+
* Focusing on what is best for the community
|
|
20
|
+
|
|
21
|
+
Examples of unacceptable behavior:
|
|
22
|
+
|
|
23
|
+
* Trolling, insulting or derogatory comments, and personal or political attacks
|
|
24
|
+
* Public or private harassment
|
|
25
|
+
* Publishing others' private information without explicit permission
|
|
26
|
+
* Other conduct which could reasonably be considered inappropriate
|
|
27
|
+
|
|
28
|
+
## Enforcement
|
|
29
|
+
|
|
30
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
31
|
+
reported to the project maintainer at **dperezcabrera@gmail.com**.
|
|
32
|
+
|
|
33
|
+
## Attribution
|
|
34
|
+
|
|
35
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contributing to pico-server-auth
|
|
2
|
+
|
|
3
|
+
## Development setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/dperezcabrera/pico-server-auth.git
|
|
7
|
+
cd pico-server-auth
|
|
8
|
+
python -m venv .venv && source .venv/bin/activate
|
|
9
|
+
pip install -e ".[dev]"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Running tests
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pytest tests/ -v
|
|
16
|
+
pytest --cov=pico_server_auth --cov-report=term-missing tests/
|
|
17
|
+
tox
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Linting
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
ruff check src/ tests/
|
|
24
|
+
ruff format src/ tests/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Code style
|
|
28
|
+
|
|
29
|
+
- Python 3.11+
|
|
30
|
+
- See AGENTS.md for conventions
|
|
31
|
+
- Single-line commit messages
|
|
32
|
+
|
|
33
|
+
## What NOT to do
|
|
34
|
+
|
|
35
|
+
- Don't modify `_version.py` (auto-generated)
|
|
36
|
+
- Don't change `version_scheme` in pyproject.toml
|
|
37
|
+
- Don't add runtime dependencies without discussion
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 David Pérez Cabrera
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pico-server-auth
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Embeddable auth server module for the pico ecosystem — JWT issuance, wallet login, JWKS endpoint
|
|
5
|
+
Author-email: David Perez Cabrera <dperezcabrera@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dperezcabrera/pico-server-auth
|
|
8
|
+
Project-URL: Documentation, https://dperezcabrera.github.io/pico-server-auth/
|
|
9
|
+
Project-URL: Repository, https://github.com/dperezcabrera/pico-server-auth
|
|
10
|
+
Project-URL: Changelog, https://github.com/dperezcabrera/pico-server-auth/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issue Tracker, https://github.com/dperezcabrera/pico-server-auth/issues
|
|
12
|
+
Keywords: auth,jwt,wallet,challenge-response,jwks,ml-dsa-65,ed25519,secp256k1,post-quantum,pico-ioc,pico-boot,dependency-injection
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Framework :: AsyncIO
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
23
|
+
Classifier: Operating System :: OS Independent
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: pico-ioc[yaml]>=2.2.0
|
|
28
|
+
Requires-Dist: pico-boot>=0.1.0
|
|
29
|
+
Requires-Dist: pico-fastapi>=0.1.0
|
|
30
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
31
|
+
Requires-Dist: cryptography>=42.0.0
|
|
32
|
+
Requires-Dist: pydantic>=2.0.0
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff>=0.9.0; extra == "dev"
|
|
38
|
+
Requires-Dist: httpx; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
# pico-server-auth
|
|
42
|
+
|
|
43
|
+
[](https://pypi.org/project/pico-server-auth/)
|
|
44
|
+
[](https://deepwiki.com/dperezcabrera/pico-server-auth)
|
|
45
|
+
[](https://opensource.org/licenses/MIT)
|
|
46
|
+

|
|
47
|
+
[](https://codecov.io/gh/dperezcabrera/pico-server-auth)
|
|
48
|
+
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-server-auth)
|
|
49
|
+
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-server-auth)
|
|
50
|
+
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-server-auth)
|
|
51
|
+
[](https://pepy.tech/projects/pico-server-auth)
|
|
52
|
+
[](https://dperezcabrera.github.io/pico-server-auth/)
|
|
53
|
+
[](https://dperezcabrera.github.io/pico-learn/)
|
|
54
|
+
|
|
55
|
+
Embeddable auth server module for the [pico-boot](https://github.com/dperezcabrera/pico-boot) ecosystem.
|
|
56
|
+
|
|
57
|
+
Issues JWT tokens, handles wallet challenge-response login, and exposes JWKS — all compatible with [pico-client-auth](https://github.com/dperezcabrera/pico-client-auth) validation.
|
|
58
|
+
|
|
59
|
+
## Two deployment modes
|
|
60
|
+
|
|
61
|
+
**Embedded** — add to any pico-boot app, auth runs in the same process:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
container = init(modules=["myapp", "pico_server_auth"], config=config)
|
|
65
|
+
# /auth/jwks, /auth/challenge, /auth/wallet, /auth/login — all available
|
|
66
|
+
# pico-client-auth validates tokens from the same JWKS
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Standalone** — deploy as a separate auth service (like pico-auth):
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
container = init(modules=["pico_server_auth"], config=config)
|
|
73
|
+
app = container.get(FastAPI)
|
|
74
|
+
# Other services point pico-client-auth JWKS to this service's /auth/jwks
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Endpoints
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
GET /auth/jwks JWKS public keys (pico-client-auth fetches this)
|
|
81
|
+
POST /auth/challenge Request nonce for wallet login
|
|
82
|
+
POST /auth/wallet Verify wallet signature, issue JWT
|
|
83
|
+
POST /auth/login Password login (admin bootstrap)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Wallet login flow
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Client pico-server-auth
|
|
90
|
+
│ │
|
|
91
|
+
│ POST /auth/challenge │
|
|
92
|
+
│ { address: "0x..." } │
|
|
93
|
+
│───────────────────────────>│
|
|
94
|
+
│ { challenge: "<nonce>" } │
|
|
95
|
+
│<───────────────────────────│
|
|
96
|
+
│ │
|
|
97
|
+
│ sign(nonce) with wallet │
|
|
98
|
+
│ │
|
|
99
|
+
│ POST /auth/wallet │
|
|
100
|
+
│ { address, public_key, │
|
|
101
|
+
│ signature, challenge, │
|
|
102
|
+
│ algorithm: "ML-DSA-65" } │
|
|
103
|
+
│───────────────────────────>│
|
|
104
|
+
│ { access_token, address } │
|
|
105
|
+
│<───────────────────────────│
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Supported wallet algorithms
|
|
109
|
+
|
|
110
|
+
| Algorithm | Type | Library |
|
|
111
|
+
|-----------|------|---------|
|
|
112
|
+
| ML-DSA-65 | Post-quantum lattice (FIPS 204) | `cryptography` |
|
|
113
|
+
| Ed25519 | Edwards curve | `cryptography` |
|
|
114
|
+
| secp256k1 | Elliptic curve (ECDSA) | `cryptography` |
|
|
115
|
+
|
|
116
|
+
## Compatibility with pico-client-auth
|
|
117
|
+
|
|
118
|
+
Tokens issued by pico-server-auth are standard JWT (RS256). pico-client-auth validates them by fetching JWKS from the `/auth/jwks` endpoint.
|
|
119
|
+
|
|
120
|
+
**Same process**: pico-client-auth discovers the JWKS endpoint automatically (same FastAPI app).
|
|
121
|
+
|
|
122
|
+
**Separate processes**: configure pico-client-auth to point to the server:
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
auth_client:
|
|
126
|
+
issuer: "http://auth-server:8100"
|
|
127
|
+
audience: "pico"
|
|
128
|
+
# JWKS fetched from http://auth-server:8100/auth/jwks
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Challenge store
|
|
132
|
+
|
|
133
|
+
By default, challenges are stored in memory with TTL expiry. For multi-instance deployments, register a custom `ChallengeStore` component:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
@component
|
|
137
|
+
class RedisChallengeStore:
|
|
138
|
+
async def create(self, address: str) -> str: ...
|
|
139
|
+
async def validate(self, address: str, nonce: str) -> bool: ...
|
|
140
|
+
async def cleanup(self) -> int: ...
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The in-memory default is replaced automatically via `on_missing_selector`.
|
|
144
|
+
|
|
145
|
+
## Configuration
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
server_auth:
|
|
149
|
+
issuer: "http://localhost:8100"
|
|
150
|
+
audience: "pico"
|
|
151
|
+
algorithm: "RS256"
|
|
152
|
+
access_token_expire_minutes: 15
|
|
153
|
+
challenge_ttl_seconds: 60
|
|
154
|
+
supported_wallet_algorithms:
|
|
155
|
+
- "ML-DSA-65"
|
|
156
|
+
- "Ed25519"
|
|
157
|
+
- "secp256k1"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Stack
|
|
161
|
+
|
|
162
|
+
- [pico-ioc](https://github.com/dperezcabrera/pico-ioc) — dependency injection
|
|
163
|
+
- [pico-boot](https://github.com/dperezcabrera/pico-boot) — auto-discovery
|
|
164
|
+
- [pico-fastapi](https://github.com/dperezcabrera/pico-fastapi) — controllers
|
|
165
|
+
- [pico-client-auth](https://github.com/dperezcabrera/pico-client-auth) — token validation
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|