authmate 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.
Files changed (54) hide show
  1. authmate-0.1.0/.gitignore +11 -0
  2. authmate-0.1.0/LICENSE +21 -0
  3. authmate-0.1.0/PKG-INFO +128 -0
  4. authmate-0.1.0/README.md +108 -0
  5. authmate-0.1.0/docs/plans/API_DESIGN.md +91 -0
  6. authmate-0.1.0/docs/plans/ARCHITECTURE.md +73 -0
  7. authmate-0.1.0/docs/plans/AUTHENTICATION.md +122 -0
  8. authmate-0.1.0/docs/plans/CONSUMER_CONTRACTS.md +69 -0
  9. authmate-0.1.0/docs/plans/CREDENTIALS_AND_SECRETS.md +100 -0
  10. authmate-0.1.0/docs/plans/DEPENDENCY_STRATEGY.md +50 -0
  11. authmate-0.1.0/docs/plans/DESIGN_DECISIONS.md +71 -0
  12. authmate-0.1.0/docs/plans/EXTENSIBILITY.md +112 -0
  13. authmate-0.1.0/docs/plans/FASTAPI_STRATEGY.md +55 -0
  14. authmate-0.1.0/docs/plans/HEDRON_INTEGRATION.md +38 -0
  15. authmate-0.1.0/docs/plans/IDENTITY_AND_AUTHORIZATION.md +144 -0
  16. authmate-0.1.0/docs/plans/MIGRATIONS.md +86 -0
  17. authmate-0.1.0/docs/plans/MVP.md +63 -0
  18. authmate-0.1.0/docs/plans/PHASE_0_1_IMPLEMENTATION_PLAN.md +858 -0
  19. authmate-0.1.0/docs/plans/PLAN_REVIEW.md +57 -0
  20. authmate-0.1.0/docs/plans/PYDANTIC_STRATEGY.md +36 -0
  21. authmate-0.1.0/docs/plans/README.md +51 -0
  22. authmate-0.1.0/docs/plans/ROADMAP.md +251 -0
  23. authmate-0.1.0/docs/plans/SECURITY_AND_AUDIT.md +100 -0
  24. authmate-0.1.0/docs/plans/SHUETL_INTEGRATION.md +57 -0
  25. authmate-0.1.0/docs/plans/VISION.md +29 -0
  26. authmate-0.1.0/docs/quickstart.md +64 -0
  27. authmate-0.1.0/examples/background_authorization.py +49 -0
  28. authmate-0.1.0/examples/report_consumer.py +80 -0
  29. authmate-0.1.0/pyproject.toml +104 -0
  30. authmate-0.1.0/src/authmate/__init__.py +58 -0
  31. authmate-0.1.0/src/authmate/errors.py +75 -0
  32. authmate-0.1.0/src/authmate/fastapi.py +110 -0
  33. authmate-0.1.0/src/authmate/models.py +336 -0
  34. authmate-0.1.0/src/authmate/protocols.py +78 -0
  35. authmate-0.1.0/src/authmate/py.typed +0 -0
  36. authmate-0.1.0/src/authmate/secrets.py +57 -0
  37. authmate-0.1.0/src/authmate/service.py +256 -0
  38. authmate-0.1.0/tests/__init__.py +1 -0
  39. authmate-0.1.0/tests/contract/__init__.py +1 -0
  40. authmate-0.1.0/tests/contract/fakes.py +94 -0
  41. authmate-0.1.0/tests/integration/__init__.py +1 -0
  42. authmate-0.1.0/tests/integration/test_documentation.py +25 -0
  43. authmate-0.1.0/tests/integration/test_examples.py +10 -0
  44. authmate-0.1.0/tests/integration/test_fastapi.py +122 -0
  45. authmate-0.1.0/tests/packaging/__init__.py +1 -0
  46. authmate-0.1.0/tests/packaging/test_package.py +43 -0
  47. authmate-0.1.0/tests/property/__init__.py +1 -0
  48. authmate-0.1.0/tests/property/test_properties.py +26 -0
  49. authmate-0.1.0/tests/static/invalid_provider.py +7 -0
  50. authmate-0.1.0/tests/unit/__init__.py +1 -0
  51. authmate-0.1.0/tests/unit/test_models.py +146 -0
  52. authmate-0.1.0/tests/unit/test_secrets.py +37 -0
  53. authmate-0.1.0/tests/unit/test_service.py +407 -0
  54. authmate-0.1.0/uv.lock +1319 -0
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ dist/
3
+ build/
4
+ *.egg-info/
5
+ __pycache__/
6
+ .pytest_cache/
7
+ .mypy_cache/
8
+ .ruff_cache/
9
+ .coverage
10
+ htmlcov/
11
+ .hypothesis/
authmate-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AuthMate contributors
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,128 @@
1
+ Metadata-Version: 2.4
2
+ Name: authmate
3
+ Version: 0.1.0
4
+ Summary: FastAPI-native identity and authorization contracts
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Classifier: Development Status :: 2 - Pre-Alpha
8
+ Classifier: Framework :: FastAPI
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Typing :: Typed
16
+ Requires-Python: <3.15,>=3.11
17
+ Requires-Dist: fastapi<1,>=0.140
18
+ Requires-Dist: pydantic<3,>=2.12
19
+ Description-Content-Type: text/markdown
20
+
21
+ # AuthMate
22
+
23
+ AuthMate is a provider-neutral authorization boundary for Python services. Version
24
+ 0.1.0 is a stateless contract preview: it validates shared values, coordinates
25
+ principal and authorization providers, and supplies a small FastAPI adapter. It
26
+ does not authenticate requests, persist data, implement RBAC, manage credentials,
27
+ or provide a production-readiness guarantee.
28
+
29
+ > Independent by default, composable by contract.
30
+
31
+ ## Status
32
+
33
+ The phase 0.1 runtime is implemented under `src/authmate`. Read the
34
+ [quickstart](docs/quickstart.md) and [planning index](docs/plans/README.md) for the
35
+ public contract and release boundary.
36
+
37
+ ## Supported runtime
38
+
39
+ Python 3.11 through 3.14. Install this checkout with `uv sync --group dev`.
40
+ AuthMate is distributed under the [MIT License](LICENSE).
41
+
42
+ ## Quick start
43
+
44
+ Providers are host-owned and implement the protocols in `authmate.protocols`.
45
+ The service calls the principal provider first, then the authorization provider
46
+ only for an enabled, non-expired principal.
47
+
48
+ ```python
49
+ from uuid import uuid4
50
+ from authmate import (
51
+ AccessContext,
52
+ AuthMate,
53
+ AuthorizationDecision,
54
+ PrincipalKind,
55
+ PrincipalRecord,
56
+ PrincipalRef,
57
+ )
58
+
59
+ actor = PrincipalRef(id=uuid4(), kind=PrincipalKind.USER)
60
+
61
+
62
+ class Principals:
63
+ async def get_principal(self, ref):
64
+ return PrincipalRecord(ref=ref, display_name="Ada", enabled=True)
65
+
66
+ async def aclose(self):
67
+ pass
68
+
69
+
70
+ class Policy:
71
+ async def authorize(self, *, principal, action, resource):
72
+ return AuthorizationDecision(
73
+ allowed=True, reason="allowed", action=action, resource=resource
74
+ )
75
+
76
+ async def aclose(self):
77
+ pass
78
+
79
+
80
+ async def check_request():
81
+ service = AuthMate(principal_provider=Principals(), authorization_provider=Policy())
82
+ try:
83
+ return await service.require(context=AccessContext(actor=actor), action="report.read")
84
+ finally:
85
+ await service.aclose()
86
+ ```
87
+
88
+ See [the phase 0.1 quickstart](docs/quickstart.md) for FastAPI integration,
89
+ provider contracts, lifecycle behavior, and deliberate non-goals.
90
+
91
+ ## Development
92
+
93
+ ```sh
94
+ uv sync --frozen --group dev
95
+ uv run ruff format --check .
96
+ uv run ruff check .
97
+ uv run mypy --strict src/authmate tests
98
+ uv run pytest --cov=authmate --cov-branch --cov-fail-under=95
99
+ uv build
100
+ uv run twine check dist/*
101
+ ```
102
+
103
+ ## Planned MVP
104
+
105
+ - Users, operator provisioning, opaque SQL-backed browser sessions, and revocation.
106
+ - Service accounts, revocable API tokens, and generic delegated identity.
107
+ - Exact RBAC scopes, FastAPI dependencies, and Python service APIs.
108
+ - Credential metadata, exact secret-use grants, and approved environment references.
109
+ - Durable SQL audit, rate limiting, CSRF protection, and explicit recovery procedures.
110
+ - Typed public contracts, controlled model/provider extensions, and reviewed migrations.
111
+
112
+ PostgreSQL is the production reference; SQLite supports local development. No Redis,
113
+ broker, external identity service, or external secret manager is required. Encrypted
114
+ SQL secret storage, federation, tenancy, and richer extensions have later release gates.
115
+
116
+ ## Architecture principles
117
+
118
+ - AuthMate owns its security semantics and public contracts; consumers adapt to them.
119
+ - Mandatory service checks remain authoritative with custom providers.
120
+ - Pydantic public contracts are separate from SQLModel/SQLAlchemy persistence.
121
+ - FastAPI composition uses explicit DI, lifespan, security, and OpenAPI integration.
122
+ - Core requires SQL-backed state, not process-local caches or additional services.
123
+
124
+ Hedron, ShuETL, and other applications may build optional adapters against AuthMate.
125
+ Core contains no consumer workflow records, callbacks, domain imports, or release
126
+ dependencies. Consumer-owned compatibility tests establish supported combinations.
127
+ See [Consumer Contracts](docs/plans/CONSUMER_CONTRACTS.md) and
128
+ [MVP gates](docs/plans/MVP.md).
@@ -0,0 +1,108 @@
1
+ # AuthMate
2
+
3
+ AuthMate is a provider-neutral authorization boundary for Python services. Version
4
+ 0.1.0 is a stateless contract preview: it validates shared values, coordinates
5
+ principal and authorization providers, and supplies a small FastAPI adapter. It
6
+ does not authenticate requests, persist data, implement RBAC, manage credentials,
7
+ or provide a production-readiness guarantee.
8
+
9
+ > Independent by default, composable by contract.
10
+
11
+ ## Status
12
+
13
+ The phase 0.1 runtime is implemented under `src/authmate`. Read the
14
+ [quickstart](docs/quickstart.md) and [planning index](docs/plans/README.md) for the
15
+ public contract and release boundary.
16
+
17
+ ## Supported runtime
18
+
19
+ Python 3.11 through 3.14. Install this checkout with `uv sync --group dev`.
20
+ AuthMate is distributed under the [MIT License](LICENSE).
21
+
22
+ ## Quick start
23
+
24
+ Providers are host-owned and implement the protocols in `authmate.protocols`.
25
+ The service calls the principal provider first, then the authorization provider
26
+ only for an enabled, non-expired principal.
27
+
28
+ ```python
29
+ from uuid import uuid4
30
+ from authmate import (
31
+ AccessContext,
32
+ AuthMate,
33
+ AuthorizationDecision,
34
+ PrincipalKind,
35
+ PrincipalRecord,
36
+ PrincipalRef,
37
+ )
38
+
39
+ actor = PrincipalRef(id=uuid4(), kind=PrincipalKind.USER)
40
+
41
+
42
+ class Principals:
43
+ async def get_principal(self, ref):
44
+ return PrincipalRecord(ref=ref, display_name="Ada", enabled=True)
45
+
46
+ async def aclose(self):
47
+ pass
48
+
49
+
50
+ class Policy:
51
+ async def authorize(self, *, principal, action, resource):
52
+ return AuthorizationDecision(
53
+ allowed=True, reason="allowed", action=action, resource=resource
54
+ )
55
+
56
+ async def aclose(self):
57
+ pass
58
+
59
+
60
+ async def check_request():
61
+ service = AuthMate(principal_provider=Principals(), authorization_provider=Policy())
62
+ try:
63
+ return await service.require(context=AccessContext(actor=actor), action="report.read")
64
+ finally:
65
+ await service.aclose()
66
+ ```
67
+
68
+ See [the phase 0.1 quickstart](docs/quickstart.md) for FastAPI integration,
69
+ provider contracts, lifecycle behavior, and deliberate non-goals.
70
+
71
+ ## Development
72
+
73
+ ```sh
74
+ uv sync --frozen --group dev
75
+ uv run ruff format --check .
76
+ uv run ruff check .
77
+ uv run mypy --strict src/authmate tests
78
+ uv run pytest --cov=authmate --cov-branch --cov-fail-under=95
79
+ uv build
80
+ uv run twine check dist/*
81
+ ```
82
+
83
+ ## Planned MVP
84
+
85
+ - Users, operator provisioning, opaque SQL-backed browser sessions, and revocation.
86
+ - Service accounts, revocable API tokens, and generic delegated identity.
87
+ - Exact RBAC scopes, FastAPI dependencies, and Python service APIs.
88
+ - Credential metadata, exact secret-use grants, and approved environment references.
89
+ - Durable SQL audit, rate limiting, CSRF protection, and explicit recovery procedures.
90
+ - Typed public contracts, controlled model/provider extensions, and reviewed migrations.
91
+
92
+ PostgreSQL is the production reference; SQLite supports local development. No Redis,
93
+ broker, external identity service, or external secret manager is required. Encrypted
94
+ SQL secret storage, federation, tenancy, and richer extensions have later release gates.
95
+
96
+ ## Architecture principles
97
+
98
+ - AuthMate owns its security semantics and public contracts; consumers adapt to them.
99
+ - Mandatory service checks remain authoritative with custom providers.
100
+ - Pydantic public contracts are separate from SQLModel/SQLAlchemy persistence.
101
+ - FastAPI composition uses explicit DI, lifespan, security, and OpenAPI integration.
102
+ - Core requires SQL-backed state, not process-local caches or additional services.
103
+
104
+ Hedron, ShuETL, and other applications may build optional adapters against AuthMate.
105
+ Core contains no consumer workflow records, callbacks, domain imports, or release
106
+ dependencies. Consumer-owned compatibility tests establish supported combinations.
107
+ See [Consumer Contracts](docs/plans/CONSUMER_CONTRACTS.md) and
108
+ [MVP gates](docs/plans/MVP.md).
@@ -0,0 +1,91 @@
1
+ # API Design
2
+
3
+ Status: proposed MVP surface, not an implemented API. The configurable router
4
+ prefix defaults to `/api/auth`; all paths below include that prefix exactly once.
5
+ All body-bearing mutations use explicit JSON schemas. No OAuth2 password-grant or
6
+ refresh endpoint is implied by local session login.
7
+
8
+ ## Authentication and sessions
9
+
10
+ | Method and path | Authority / behavior |
11
+ | --- | --- |
12
+ | `POST /api/auth/login` | Public but origin-checked and rate-limited; sets opaque session cookie |
13
+ | `GET /api/auth/me` | Current authenticated principal; redacted response |
14
+ | `GET /api/auth/csrf` | Browser session; returns session-bound CSRF value, no-store |
15
+ | `POST /api/auth/logout` | Browser session + CSRF; SQL revocation then cookie clear |
16
+ | `POST /api/auth/password/change` | User session + CSRF + current password; revokes sessions |
17
+ | `GET /api/auth/sessions` | User's own session metadata |
18
+ | `DELETE /api/auth/sessions/{id}` | User's own session only; revoke, never disclose token |
19
+
20
+ Expired/invalid sessions return 401. A restricted temporary-password session can
21
+ only obtain its CSRF value, change its password, or log out. Login, logout, and CSRF behavior is defined in
22
+ [Authentication](AUTHENTICATION.md). No public registration, recovery, or bootstrap
23
+ route is included in MVP.
24
+
25
+ ## Management routes and permission matrix
26
+
27
+ Each listed permission has the `authmate.` prefix. User/service-account/credential
28
+ creation and top-level listing use realm-level `.create` / `.list` actions; `.manage`
29
+ applies to existing-object read/edit. Roles and role bindings use realm-level
30
+ management actions for all their routes. Nested token/grant operations use their
31
+ parent resource. These are distinct registered actions, not implied suffix matching.
32
+
33
+ | Paths and methods | Permission | Resource type |
34
+ | --- | --- | --- |
35
+ | `POST, GET /api/auth/users` | `user.create`, `user.list` respectively | realm-level actions |
36
+ | `GET, PATCH /api/auth/users/{id}` | `user.manage` | `authmate.user` |
37
+ | `POST /api/auth/users/{id}/disable`, `/enable` | `user.disable` | `authmate.user` |
38
+ | `POST /api/auth/users/{id}/password-reset` | `user.password.reset` | `authmate.user` |
39
+ | `POST, GET /api/auth/roles`; `GET, PATCH /api/auth/roles/{id}` | `role.manage` | realm-level actions |
40
+ | `POST, GET /api/auth/role-bindings`; `DELETE /api/auth/role-bindings/{id}` | `role_binding.manage` | realm-level actions |
41
+ | `POST, GET /api/auth/service-accounts` | `service_account.create`, `service_account.list` respectively | realm-level actions |
42
+ | `GET, PATCH /api/auth/service-accounts/{id}` | `service_account.manage` | `authmate.service_account` |
43
+ | `POST /api/auth/service-accounts/{id}/disable`, `/enable` | `service_account.disable` | `authmate.service_account` |
44
+ | `POST, GET /api/auth/service-accounts/{id}/tokens`; `DELETE /api/auth/service-accounts/{id}/tokens/{token_id}` | `service_account.token.manage` | `authmate.service_account` |
45
+ | `POST, GET /api/auth/credentials` | `credential.create`, `credential.list` respectively | realm-level actions |
46
+ | `GET, PATCH /api/auth/credentials/{id}`; `POST /api/auth/credentials/{id}/disable`, `/enable` | `credential.manage` | `authmate.credential` |
47
+ | `GET /api/auth/credentials/{id}` (alternative read-only authority) | `credential.read_metadata` | `authmate.credential` |
48
+ | `POST, GET /api/auth/credentials/{id}/grants`; `DELETE /api/auth/credentials/{id}/grants/{grant_id}` | `credential.grant.manage` | `authmate.credential` |
49
+ | `GET /api/auth/audit-events` | `audit.read` | realm-level action |
50
+
51
+ A management role explicitly includes all required create/list/manage entries;
52
+ there is no implicit permission hierarchy. Do not overload `resource=None` to
53
+ authorize a resource action. Credential detail can use either listed authority;
54
+ that OR is explicit and grants no secret access. Grant deletion also checks that
55
+ the supplied grant ID belongs to the authorized parent credential.
56
+
57
+ `authmate.service_account.assume` is a resource permission assigned through ordinary
58
+ role bindings. It governs generic delegated service calls, not a workload binding
59
+ API. Consumer workflow/approval records never become AuthMate management endpoints.
60
+
61
+ The environment provider is read-only. No secret upload, secret read, or rotation
62
+ route ships in MVP. A later writable-provider API requires capability-specific
63
+ schemas and the encrypted-provider release gate. Service-account token creation
64
+ is a deliberate one-time secret response; all other reads return metadata only.
65
+
66
+ ## Enforcement and error contract
67
+
68
+ Use APIRouter, explicit Pydantic request/response models, and server-side service
69
+ checks even for in-process callers. PATCH schemas allowlist editable fields and
70
+ reject unknown/reserved fields. Require version/If-Match on concurrent metadata,
71
+ role, and grant-policy edits; stale writes return 409. DELETE/revocation operations
72
+ are idempotent within caller authority; nested IDs must belong to the parent object.
73
+
74
+ Collection routes require the corresponding realm list/management/audit authority;
75
+ credential grants and tokens are scoped to their parent. Authorize/filter in SQL before
76
+ pagination/counts. Own a bounded Page schema: default 50, maximum 100, deterministic
77
+ sort with ID tie-breaker, and opaque cursor where supported. Audit paging uses a
78
+ stable time/ID cursor. A cursor is an untrusted input, never authorization evidence.
79
+
80
+ Errors use `{ "code": "...", "message": "...", "request_id": "..." }`.
81
+ Return 401 for invalid/missing identity, 403 for known prohibited operations, 404
82
+ for missing or undiscoverable detail resources, 409 for stale/conflicting writes,
83
+ 422 for sanitized validation failures, 429 for throttling, and 503 for security
84
+ state/provider/audit unavailability. Reject unsupported JSON media types before
85
+ service invocation (415). Use WWW-Authenticate on bearer 401 responses. Do not expose
86
+ SQL/provider exceptions, raw rejected input, hashes, tokens, or permission internals.
87
+
88
+ Document cookie/CSRF and HTTP bearer schemes truthfully in OpenAPI. Resource RBAC
89
+ is checked by services; OAuth scopes do not encode it. Auth/session/token responses
90
+ use Cache-Control: no-store. AuthMate-scoped error handling must not overwrite the
91
+ host application's handlers globally; see [FastAPI Strategy](FASTAPI_STRATEGY.md).
@@ -0,0 +1,73 @@
1
+ # Architecture
2
+
3
+ AuthMate is an embeddable FastAPI identity, authorization, and credential package.
4
+ It defines its own public contracts independently of consumer applications.
5
+
6
+ ```text
7
+ FastAPI routers/dependencies Trusted Python/background callers
8
+ \ /
9
+ AuthMate service facade
10
+ / | \
11
+ Identity Authorization Credentials
12
+ \ | /
13
+ SQL unit of work + audit
14
+ | \
15
+ Persistence Secret-provider adapters
16
+ ```
17
+
18
+ Mandatory checks live in service wrappers, so direct Python calls cannot accidentally
19
+ skip rules enforced only by HTTP routes. Providers supply mechanisms behind those
20
+ checks. Audit is part of each protected operation, not an asynchronous afterthought.
21
+ Secret-provider I/O is bounded and happens outside held SQL write locks; release
22
+ requires a final current-state check and committed audit event.
23
+
24
+ ## Composition and contracts
25
+
26
+ FastAPI dependencies handle current identity, permission enforcement, and resource
27
+ lookup. A resource-specific dependency must derive its ResourceRef from a trusted
28
+ lookup; `require_permission("myapp.report.read")` without a resource is insufficient
29
+ for an exact-resource action. Python `can`, `authorize`, `require`, and credential
30
+ resolution use explicit context and do not need HTTP request state.
31
+
32
+ [Consumer Contracts](CONSUMER_CONTRACTS.md) defines PrincipalRef, AccessContext,
33
+ ResourceRef, decisions, provider protocols, and lifecycle/error semantics. Consumers
34
+ register generic action/resource namespaces and adapt their own APIs to AuthMate.
35
+ Core never imports Hedron, ShuETL, ETLantic, or their ORM/domain models. Their adapters
36
+ and compatibility tests are consumer-owned and cannot block a core release.
37
+
38
+ AuthMate owns identity/security semantics and reuses maintained hashing, validation,
39
+ SQL, and optional cryptographic/protocol libraries behind implementation adapters.
40
+ Public Pydantic values remain separate from persistence/provider objects. SQLModel
41
+ models represent ordinary internal tables; SQLAlchemy handles explicit transactions,
42
+ async sessions, locking, and advanced queries.
43
+
44
+ ## Deployment and state
45
+
46
+ Default production deployment is one or more FastAPI processes plus PostgreSQL.
47
+ SQLite is a local-development backend. SQL stores session/token digests, security
48
+ state, roles/grants, credential metadata, rate-limit state, and durable audit. Correctness
49
+ never relies on process-local positive caches, a cleanup timer, Redis, or a broker.
50
+
51
+ Environment-backed secret references are the MVP provider. External identity/secret
52
+ services and the encrypted SQL provider are optional later capabilities. Process
53
+ configuration, TLS, operator-provisioned secrets, backups, and reviewed migrations
54
+ remain deployment responsibilities even though no additional service is mandatory.
55
+
56
+ Each AuthMate instance has its own explicit configuration/provider registry and unit
57
+ of work. No module-global current user, service locator, or shared request session.
58
+ Host lifespan explicitly enters/closes AuthMate resources; failed startup cleans up
59
+ partially opened providers. Async sessions never outlive their operation or cross
60
+ concurrent tasks. See [FastAPI Strategy](FASTAPI_STRATEGY.md).
61
+
62
+ ## Schema and isolation
63
+
64
+ AuthMate owns only its registered `authmate_*` tables and migration history, even
65
+ when it shares a database with consumers. User/service-account metadata extensions
66
+ use a validated model registry and reviewed migrations. Production startup verifies
67
+ schema compatibility; it does not generate or automatically apply DDL. See
68
+ [Persistence and Managed Migrations](MIGRATIONS.md).
69
+
70
+ MVP supports one security realm per deployment. Namespaces partition action names,
71
+ not tenants. Generic resource strings or custom claims do not establish tenant
72
+ isolation. Strong tenant boundaries require a future schema/contract design or
73
+ separate deployments today.
@@ -0,0 +1,122 @@
1
+ # Authentication and Sessions
2
+
3
+ Status: selected MVP design; implementation and security gates remain open.
4
+
5
+ ## Default transport and state
6
+
7
+ MVP uses opaque, SQL-backed sessions, not self-contained JWTs or refresh tokens.
8
+ Browser login sets a cookie; it does not return a bearer token in JSON. Machine
9
+ clients use separately issued service-account API tokens. JWT/OIDC adapters and
10
+ custom token claims are later features, not prerequisites for local login.
11
+
12
+ Generate authentication tokens with 32 bytes from a CSPRNG. Store a SHA-256 digest of the random
13
+ secret, never the raw token. This fast digest is for high-entropy tokens only;
14
+ passwords use Argon2id. Use token-type prefixes and separate lookup/state tables
15
+ so a machine token cannot be accepted as a browser session. Never accept tokens
16
+ in query parameters. Multiple supplied authentication mechanisms are rejected
17
+ rather than resolved by implicit precedence.
18
+
19
+ Each session stores principal ID, creation/last-activity times, idle/absolute
20
+ expiry, revocation time, and the principal's authentication epoch at issuance.
21
+ Create a fresh session ID on every successful login; never adopt a supplied ID.
22
+ Every authenticated operation checks current SQL state, principal enabled state,
23
+ epoch, and expiry. Baseline has no process-local positive authorization cache.
24
+ Use database time for expiry and atomic conditional activity updates so races
25
+ cannot resurrect revoked or expired sessions. Proposed defaults: 30-minute idle
26
+ and 12-hour absolute lifetime; operators can shorten both. No sliding update
27
+ extends absolute expiry. OWASP motivates server-side state, unpredictable IDs,
28
+ and server-enforced expiry; these exact defaults are AuthMate design choices.
29
+ [Source: OWASP session guidance](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html).
30
+
31
+ Logout revokes the session in SQL before reporting success and clears the cookie.
32
+ Password change/reset and principal disable atomically increment the authentication
33
+ epoch and revoke all sessions/tokens for that principal. Re-enabling never revives
34
+ old tokens. Role/grant removal affects the next authorization check through fresh
35
+ SQL evaluation, without requiring logout. See the concurrency boundary in
36
+ [Identity and Authorization](IDENTITY_AND_AUTHORIZATION.md).
37
+
38
+ ## Browser protection
39
+
40
+ Use a deployment-unique `__Host-` cookie name, `Secure`, `HttpOnly`, `SameSite=Lax`,
41
+ `Path=/`, and no Domain attribute. Plain HTTP cookies require an explicit local
42
+ development profile rejected by production readiness. Cookie paths do not isolate
43
+ mutually untrusted apps on one origin; those apps need separate origins.
44
+
45
+ For unsafe cookie-authenticated requests, require both an exact configured Origin
46
+ (or validated Referer origin fallback) and a session-bound CSRF token in a custom
47
+ header. Obtain that token through authenticated `GET /api/auth/csrf`, with no-store
48
+ responses and no permissive credentialed CORS. The CSRF value is an independent
49
+ random per-session value stored in the session row and compared in constant time;
50
+ it cannot authenticate a request and never substitutes for the opaque session cookie. Login itself requires an allowed
51
+ origin and JSON content type, including before a session exists. Logout and login
52
+ are never GET operations. Reject missing/invalid origin evidence for browser
53
+ mutations; machine bearer endpoints do not use cookie authentication. Strict JSON
54
+ content type supplements CSRF checks; it does not replace them.
55
+
56
+ Cookies, CSRF values, password inputs, and token responses are excluded from
57
+ access logs, tracing, validation error input, and caches. TLS termination and
58
+ forwarded client IP headers are trusted only from explicitly configured proxies.
59
+
60
+ ## Local users and password lifecycle
61
+
62
+ MVP login uses a unique normalized username; email is optional metadata, not an
63
+ alternate unverified login identifier. Normalize usernames once (NFKC + casefold),
64
+ store a separate display name, and enforce canonical uniqueness in SQL on both
65
+ backends. Never normalize, trim, or silently truncate passwords.
66
+
67
+ Use `pwdlib[argon2]` with explicitly configured Argon2id parameters, unique salts,
68
+ and rehash-on-success. Start at 64 MiB, 3 iterations, parallelism 1; benchmark under
69
+ bounded login concurrency before release. Never configure below the reviewed
70
+ minimum of 19 MiB, 2 iterations, parallelism 1.
71
+ [Source: OWASP password storage](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html).
72
+ Accept 15–128 Unicode characters and at most 1024 UTF-8 bytes; allow spaces and
73
+ password managers, reject a shipped common-password list, and impose no composition
74
+ rules or routine forced rotation. Password policy and hashing cost are versioned
75
+ settings, not whatever a library changes its defaults to.
76
+
77
+ Unknown users perform dummy hash verification. Unknown, disabled, and incorrect
78
+ password cases share a generic 401 response. Hash work runs off the event loop
79
+ with bounded concurrency. A SQL rate limiter reserves attempts atomically before
80
+ hashing, using independent account-name and source-IP windows. Initial defaults:
81
+ 5 attempts/account/5 minutes and 50 attempts/IP/5 minutes, including failures and
82
+ unknown users; return generic 429 with Retry-After. Bound key cardinality with a
83
+ global attempt budget and expire buckets. Tune these defaults with documented
84
+ load/abuse tests; process-local hooks are insufficient across replicas. SQL failure
85
+ denies login. Rate limiting reduces guessing but can be abused to deny service.
86
+
87
+ Self-registration, email verification, email-based recovery, MFA, and invitation
88
+ flows are deferred. Provisioning and recovery use an operator command or an
89
+ explicitly privileged management operation; never a public bootstrap endpoint.
90
+ Initial bootstrap uses a single-use SQL guard in the same transaction as the
91
+ first administrator binding and audit event, so concurrent processes cannot both
92
+ bootstrap. Input passwords through a hidden prompt/secure input, not CLI arguments
93
+ or logs. Provide an audited operator recovery procedure using database access.
94
+ An administrator can set a temporary password with a `must_change_password` flag;
95
+ that login yields only a password-change capability (plus CSRF retrieval and logout)
96
+ until successful replacement.
97
+ Self password change requires the current password and revokes existing sessions.
98
+ Hash verification happens outside SQL locks; login and password changes then acquire
99
+ the security-state guard and recheck the hash/epoch, enabled state, and restriction
100
+ flag before committing. A concurrent reset/disable invalidates the pending issuance.
101
+ Rehash-on-login uses a conditional update so it cannot overwrite a concurrent reset.
102
+
103
+ ## Service-account API tokens
104
+
105
+ A trusted co-located executor need not mint a bearer token to use a service account;
106
+ its authority comes from the generic AccessContext and assumption permission in
107
+ [Consumer Contracts](CONSUMER_CONTRACTS.md). An arbitrary principal ID is not proof
108
+ of authority at an HTTP or job boundary.
109
+
110
+ Remote clients may receive an opaque API token only through a caller with
111
+ `authmate.service_account.token.manage` on that account. This permission permits
112
+ impersonation and is distinct from metadata editing. Reveal the token exactly once
113
+ in the creation response, with Cache-Control: no-store. Store its digest, account
114
+ ID, creation/expiry/revocation timestamps, authentication epoch, and display prefix.
115
+ Default expiry is 24 hours with a configurable finite maximum of 30 days. Tokens
116
+ inherit the account's current permissions; narrower token scopes are deferred and
117
+ must not be implied. Use separate accounts for distinct privilege sets.
118
+
119
+ API-token rotation creates a new token and explicitly revokes the old one; any
120
+ overlap must be bounded by an explicit expiry. Do not retry issuance automatically
121
+ after an ambiguous response; list token metadata, revoke an uncertain token, and
122
+ issue another. Token values are never recoverable from read/list endpoints.
@@ -0,0 +1,69 @@
1
+ # Consumer Contracts
2
+
3
+ Status: proposed AuthMate-owned contracts to validate through implementation.
4
+ Consumers adapt to these interfaces; consumer release schedules and domain models
5
+ do not define AuthMate core. Method names below are planned, not currently callable.
6
+
7
+ ## Public values and protocols
8
+
9
+ | Contract | Meaning and boundary |
10
+ | --- | --- |
11
+ | `PrincipalRef` / `PrincipalRecord` | Immutable ID/kind and explicitly public identity metadata; never ORM objects or authentication proof |
12
+ | `AuthenticationResult` | Validated actor identity plus mechanism/time/assurance from a trusted authenticator |
13
+ | `AccessContext` | Verified actor and optional effective service account; generic delegation is validated by AuthMate |
14
+ | `ResourceRef` | Exact registered type and canonical ID supplied by a trusted consumer lookup |
15
+ | `AuthorizationDecision` | Allow/deny with safe reason and diagnostic policy revision; a snapshot, not a capability |
16
+ | `PrincipalProvider` | Fetch current principal state through authorized service access; a returned ID does not authorize impersonation |
17
+ | `AuthorizationProvider` | Evaluate default RBAC or a selected custom policy inside mandatory AuthMate checks |
18
+ | `CredentialResolver` | Resolve an exact credential for AccessContext after current-state checks and durable audit |
19
+ | `SecretProvider` | Low-level backend mechanics behind CredentialResolver; not a public authorization bypass |
20
+ | `AuditSink` | Optional delivery target for already committed typed events; SQL audit remains authoritative |
21
+
22
+ Public service operations take explicit context and parameters, use async contracts,
23
+ and raise typed AuthMate domain errors. `can()` is advisory; `authorize()` returns a
24
+ decision; `require()` enforces or raises. FastAPI dependencies adapt transport to
25
+ these services. Background callers use the same services without constructing an
26
+ HTTP Request or depending on a request-scoped database session.
27
+
28
+ ## Delegation and credentials
29
+
30
+ For direct use, actor equals effective principal. For delegated use, the authenticated
31
+ actor must hold `authmate.service_account.assume` on the effective account, and that
32
+ account must independently hold the requested permission or exact credential-use
33
+ grant. AuthMate checks both principals' current state. Assumption does not union
34
+ roles, authorize arbitrary token issuance, or recursively assume another account.
35
+
36
+ An executor, automation, or administrative tool can use this generic contract.
37
+ AuthMate does not require a pipeline, job, schedule, approved-version field, or
38
+ consumer callback. The consumer owns constraints tying its operation to the chosen
39
+ account/resource/credential. Correlation and initiating-user metadata are audit
40
+ context only and cannot authenticate an actor or broaden its authority.
41
+
42
+ ## Ownership
43
+
44
+ AuthMate owns authentication, current principal state, role/scope semantics, generic
45
+ assumption permission, credential grants, secret release, and its audit/SQL schema.
46
+ Consumers own their resource existence, action registration/mapping, workflow
47
+ approval, domain data, execution lifecycle, output redaction, and any additional
48
+ business rules. They must enforce their rules before external effects and cannot
49
+ turn UI visibility or a prior decision into durable authorization.
50
+
51
+ An adapter belongs with the consumer or in a separate package depending on both
52
+ published APIs. No consumer-specific imports, schema, feature checks, validation
53
+ callbacks, or release gates belong in core. AuthMate's conformance tests use generic
54
+ report resources and a fake background client, proving the contract without sibling
55
+ repositories. Consumer adapters run their own real-version compatibility suites.
56
+
57
+ ## Errors, lifecycle, and versioning
58
+
59
+ Distinguish unauthenticated, denied, not-found/hidden, invalid reference/config,
60
+ conflict, unsupported capability, and unavailable errors. No provider failure means
61
+ allow. Metadata and error objects must never contain resolved secrets or raw tokens.
62
+ Providers define timeout/cancellation/cleanup, and services commit mandatory audit
63
+ before acknowledging protected mutations or releasing secret material.
64
+
65
+ Registries freeze at startup; duplicate/conflicting registrations fail. Publish a
66
+ contract/schema version and a compatibility policy before stable release. Pre-1.0
67
+ changes must include migration notes and conformance updates; no promise of a frozen
68
+ protocol before the first end-to-end implementation. Adapter authors receive typed
69
+ examples and the same conformance suite used by default providers.