agent-enrollment-protocol 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 (39) hide show
  1. agent_enrollment_protocol-0.1.0/.gitignore +14 -0
  2. agent_enrollment_protocol-0.1.0/LICENSE +21 -0
  3. agent_enrollment_protocol-0.1.0/PKG-INFO +257 -0
  4. agent_enrollment_protocol-0.1.0/README.md +229 -0
  5. agent_enrollment_protocol-0.1.0/examples/README.md +31 -0
  6. agent_enrollment_protocol-0.1.0/examples/agent_service.py +355 -0
  7. agent_enrollment_protocol-0.1.0/examples/hosted_platform.py +195 -0
  8. agent_enrollment_protocol-0.1.0/pyproject.toml +100 -0
  9. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/__init__.py +7 -0
  10. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/adapters/__init__.py +29 -0
  11. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/adapters/asgi.py +445 -0
  12. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/agent/__init__.py +96 -0
  13. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/agent/client.py +934 -0
  14. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/agent/platform_provider.py +659 -0
  15. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/agent/stores.py +101 -0
  16. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/agent/transport.py +51 -0
  17. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/agent/types.py +218 -0
  18. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/__init__.py +250 -0
  19. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/assertions.py +141 -0
  20. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/claims.py +38 -0
  21. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/constants.py +46 -0
  22. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/did_web.py +77 -0
  23. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/errors.py +48 -0
  24. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/http.py +102 -0
  25. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/inspect.py +70 -0
  26. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/models.py +929 -0
  27. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/openapi.py +108 -0
  28. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/core/validation.py +77 -0
  29. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/platform/__init__.py +79 -0
  30. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/platform/document.py +158 -0
  31. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/platform/platform.py +674 -0
  32. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/platform/stores.py +219 -0
  33. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/platform/types.py +282 -0
  34. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/py.typed +1 -0
  35. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/service/__init__.py +95 -0
  36. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/service/credentials.py +355 -0
  37. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/service/service.py +871 -0
  38. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/service/stores.py +135 -0
  39. agent_enrollment_protocol-0.1.0/src/agent_enrollment_protocol/service/types.py +337 -0
@@ -0,0 +1,14 @@
1
+ /.conformance/aep-specs/
2
+ /.conformance/reports/
3
+ /.interop/
4
+ /.mypy_cache/
5
+ /.pytest_cache/
6
+ /.ruff_cache/
7
+ /.venv/
8
+ /dist/
9
+ /htmlcov/
10
+ /src/*.egg-info/
11
+ /.coverage
12
+ /coverage.xml
13
+ __pycache__/
14
+ *.py[cod]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AEP Foundation
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,257 @@
1
+ Metadata-Version: 2.5
2
+ Name: agent-enrollment-protocol
3
+ Version: 0.1.0
4
+ Summary: Official Python SDK for the Agent Enrollment Protocol
5
+ Project-URL: Documentation, https://www.aep.foundation/
6
+ Project-URL: Issues, https://github.com/aep-foundation/aep-python/issues
7
+ Project-URL: Repository, https://github.com/aep-foundation/aep-python
8
+ Author-email: Nas Kavian <nas@inflowpay.ai>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: aep,agent,authentication,enrollment,protocol
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: cryptography<51,>=50.0.1
24
+ Requires-Dist: httpx<1,>=0.28.1
25
+ Requires-Dist: pydantic<3,>=2.13.4
26
+ Requires-Dist: pyjwt<3,>=2.13.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Agent Enrollment Protocol for Python
30
+
31
+ [![CI](https://github.com/aep-foundation/aep-python/actions/workflows/ci.yml/badge.svg)](https://github.com/aep-foundation/aep-python/actions/workflows/ci.yml)
32
+ [![Python](https://img.shields.io/badge/Python-3.11%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
33
+ [![PyPI](https://img.shields.io/pypi/v/agent-enrollment-protocol)](https://pypi.org/project/agent-enrollment-protocol/)
34
+ [![Codecov](https://codecov.io/gh/aep-foundation/aep-python/graph/badge.svg)](https://codecov.io/gh/aep-foundation/aep-python)
35
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
36
+
37
+ Official Python software development kit for the
38
+ [Agent Enrollment Protocol](https://www.aep.foundation/), the open protocol for Agent enrollment,
39
+ Service-issued credentials, and authenticated Agent access.
40
+
41
+ ## Installation
42
+
43
+ ```sh
44
+ python -m pip install agent-enrollment-protocol
45
+ ```
46
+
47
+ Python 3.11 or newer is required. The distribution provides one typed package with modules for each
48
+ integration role:
49
+
50
+ | Goal | Module |
51
+ | --- | --- |
52
+ | Use protocol models, validation, identity, and assertions | `agent_enrollment_protocol.core` |
53
+ | Inspect, enroll with, and authenticate to Services | `agent_enrollment_protocol.agent` |
54
+ | Integrate enrollment and authentication into a Service | `agent_enrollment_protocol.service` |
55
+ | Host managed Agent identities and delegated signing | `agent_enrollment_protocol.platform` |
56
+
57
+ Core is synchronous and transport-independent. Agent, Service, Platform, and their integration
58
+ interfaces are asynchronous. Applications provide durable stores and security policy through typed
59
+ protocols.
60
+
61
+ Framework integrations are optional and remain separate from Core and role behavior.
62
+
63
+ ## Runnable examples
64
+
65
+ The repository includes self-contained examples that exercise real signed protocol flows without
66
+ external infrastructure:
67
+
68
+ ```sh
69
+ uv run python examples/agent_service.py
70
+ uv run python examples/hosted_platform.py
71
+ ```
72
+
73
+ The first example composes an Agent, Service, every built-in credential profile, protected resource,
74
+ and the framework-neutral ASGI adapter. The second demonstrates hosted identity Platform discovery,
75
+ Service DID resolution, provisioning, DID publication, delegated signing, and identity listing. See
76
+ [`examples/README.md`](./examples/README.md) for the integration boundaries and production
77
+ replacements.
78
+
79
+ The Service module includes stored credential profiles for each built-in Grant Type:
80
+
81
+ | Grant Type | Factory |
82
+ | --- | --- |
83
+ | API key | `stored_api_key_grant_type()` |
84
+ | Basic | `stored_basic_grant_type()` |
85
+ | OAuth Bearer | `stored_oauth_bearer_grant_type()` |
86
+
87
+ Each factory accepts application-owned credential issuance and storage implementations. The included
88
+ memory store is intended for examples and local development.
89
+
90
+ Concrete Grant Types and extensions can define additional Grant and Revoke request members. Pass
91
+ those members through `GrantOptions.parameters` or `RevokeOptions.parameters`; the Agent retains
92
+ control of the standard Grant Type and Revoke selector fields.
93
+
94
+ ## Service ASGI integration
95
+
96
+ `agent_enrollment_protocol.adapters` provides a framework-neutral ASGI integration with no
97
+ additional dependency. `AepAsgiApplication` serves Inspect and every command advertised by the
98
+ Service. It enforces the command methods, media type, request-body limit, and idempotency header
99
+ boundary, and supplies cache metadata and conditional requests for Inspect.
100
+
101
+ `AepAuthenticationMiddleware` protects a downstream ASGI application and exposes the authenticated
102
+ Agent principal through `principal_from_scope()`. Place the protocol application outside the
103
+ authentication middleware so AEP's own command routes remain directly accessible:
104
+
105
+ ```python
106
+ from agent_enrollment_protocol.adapters import (
107
+ AepAsgiApplication,
108
+ AepAuthenticationMiddleware,
109
+ principal_from_scope,
110
+ )
111
+
112
+ protected_application = AepAuthenticationMiddleware(
113
+ application,
114
+ service,
115
+ resource_origin="https://service.example",
116
+ )
117
+ asgi_application = AepAsgiApplication(service, protected_application)
118
+ ```
119
+
120
+ The downstream application can obtain its immutable principal from the ASGI scope:
121
+
122
+ ```python
123
+ principal = principal_from_scope(scope)
124
+ if principal is None:
125
+ raise RuntimeError("The route requires AEP authentication")
126
+ ```
127
+
128
+ Use a separate unprotected application branch for public resources. For local development,
129
+ `allow_insecure_loopback=True` permits an HTTP `localhost` or loopback resource origin; production
130
+ origins require HTTPS.
131
+
132
+ ## Agent with a hosted identity Platform
133
+
134
+ `PlatformIdentityProvider` lets an Agent use a remote AEP Platform for Service-scoped identity
135
+ custody and delegated assertion signing. It discovers the Platform, recovers an existing active
136
+ identity before provisioning one, caches discovery metadata according to HTTP cache directives,
137
+ and supplies the resulting signer directly to `Agent`.
138
+
139
+ ```python
140
+ import os
141
+
142
+ from agent_enrollment_protocol.agent import (
143
+ Agent,
144
+ AgentOptions,
145
+ PlatformIdentityProvider,
146
+ PlatformIdentityProviderOptions,
147
+ )
148
+
149
+
150
+ async def authentication_headers() -> dict[str, str]:
151
+ return {"Authorization": f"Bearer {os.environ['AEP_PLATFORM_ACCESS_TOKEN']}"}
152
+
153
+
154
+ async with PlatformIdentityProvider(
155
+ PlatformIdentityProviderOptions(
156
+ authentication_headers=authentication_headers,
157
+ platform_url="https://platform.example",
158
+ )
159
+ ) as identities:
160
+ async with Agent(AgentOptions(identity_provider=identities)) as agent:
161
+ result = await agent.service("https://service.example").enroll()
162
+ ```
163
+
164
+ The Platform authentication callback is evaluated for each private request so applications can
165
+ refresh short-lived credentials. Supply `pending_sign_resolver` when the Platform can return
166
+ `202 Accepted` during delegated signing. The resolver receives the immutable retry interval and
167
+ opaque Platform context; returning updated context starts the next signing stage with a distinct
168
+ idempotency key. Without a resolver, pending signing raises `PlatformSignPendingError` for the
169
+ application to continue explicitly.
170
+
171
+ ## Hosted identity Platform
172
+
173
+ `agent_enrollment_protocol.platform` implements discovery, Service-scoped Agent identity
174
+ provisioning, DID document publication, identity listing and lifecycle, delegated signing, and
175
+ optional hosted verification.
176
+
177
+ Applications supply caller authorization, Service DID resolution, key custody, and durable stores.
178
+ The included memory stores are suitable for local development, not production key custody or
179
+ durable idempotency.
180
+
181
+ ```python
182
+ from datetime import timedelta
183
+
184
+ from agent_enrollment_protocol.core import SigningAlgorithm
185
+ from agent_enrollment_protocol.platform import DiscoveryOptions, Platform, PlatformOptions
186
+
187
+ platform = Platform(
188
+ PlatformOptions(
189
+ authorizer=authorizer,
190
+ did_host="platform.example",
191
+ did_url_template="https://platform.example/agents/{agent_did_id}/did.json",
192
+ discovery=DiscoveryOptions(
193
+ endpoint_base="/v1/aep",
194
+ lifecycle_endpoint="/v1/aep/agent-identities/{agent_identity_id}",
195
+ list_endpoint="/v1/aep/agent-identities",
196
+ platform_name="Example Platform",
197
+ provision_endpoint="/v1/aep/agent-identities",
198
+ sign_endpoint="/v1/aep/agent-identities/{agent_identity_id}/sign",
199
+ ),
200
+ key_store=key_store,
201
+ maximum_lifetime=timedelta(minutes=5),
202
+ service_did_resolver=service_did_resolver,
203
+ signing_algorithms=(SigningAlgorithm.ES256,),
204
+ )
205
+ )
206
+ ```
207
+
208
+ Map `platform.discovery()` to `/.well-known/aep-platform` and the remaining methods to the paths
209
+ advertised by `DiscoveryOptions`. Authenticate private Platform routes before constructing their
210
+ `RequestContext`; the Platform also invokes the supplied authorizer for every private operation.
211
+ Enable hosted verification only with a replay store.
212
+
213
+ ## Development
214
+
215
+ Install the locked development environment and run the complete merge gate:
216
+
217
+ ```sh
218
+ uv sync --all-groups --locked
219
+ make verify
220
+ ```
221
+
222
+ Run the shared Agent, Service, and Platform conformance suites against the public Python APIs:
223
+
224
+ ```sh
225
+ make conformance
226
+ ```
227
+
228
+ The command reads the adjacent `../aep-specs` checkout by default and writes role reports to
229
+ `.conformance/reports/`. Set `AEP_SPECS_DIR` when the specifications are checked out elsewhere.
230
+
231
+ Run bidirectional Agent, Service, and Platform interoperability against the Node.js SDK:
232
+
233
+ ```sh
234
+ make interoperability
235
+ ```
236
+
237
+ The command reads the adjacent `../aep-node` checkout by default and writes a four-row evidence
238
+ report to `.interop/reports/aep-python-node-interoperability.json`. Set `AEP_NODE_DIR` when the
239
+ Node.js SDK is checked out elsewhere.
240
+
241
+ See [`aep-specs`](https://github.com/aep-foundation/aep-specs) for the normative drafts, schemas,
242
+ registries, examples, and test vectors.
243
+
244
+ ## Releases
245
+
246
+ Maintainers run the `Release` workflow from `main`. It verifies the package and a clean consumer,
247
+ runs shared conformance and Node.js interoperability, publishes through PyPI Trusted Publishing,
248
+ attests the distributions, and creates the matching tag and GitHub release with the verification
249
+ reports.
250
+
251
+ ## Security
252
+
253
+ See [SECURITY.md](./SECURITY.md) for vulnerability reporting.
254
+
255
+ ## License
256
+
257
+ MIT.
@@ -0,0 +1,229 @@
1
+ # Agent Enrollment Protocol for Python
2
+
3
+ [![CI](https://github.com/aep-foundation/aep-python/actions/workflows/ci.yml/badge.svg)](https://github.com/aep-foundation/aep-python/actions/workflows/ci.yml)
4
+ [![Python](https://img.shields.io/badge/Python-3.11%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/)
5
+ [![PyPI](https://img.shields.io/pypi/v/agent-enrollment-protocol)](https://pypi.org/project/agent-enrollment-protocol/)
6
+ [![Codecov](https://codecov.io/gh/aep-foundation/aep-python/graph/badge.svg)](https://codecov.io/gh/aep-foundation/aep-python)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
8
+
9
+ Official Python software development kit for the
10
+ [Agent Enrollment Protocol](https://www.aep.foundation/), the open protocol for Agent enrollment,
11
+ Service-issued credentials, and authenticated Agent access.
12
+
13
+ ## Installation
14
+
15
+ ```sh
16
+ python -m pip install agent-enrollment-protocol
17
+ ```
18
+
19
+ Python 3.11 or newer is required. The distribution provides one typed package with modules for each
20
+ integration role:
21
+
22
+ | Goal | Module |
23
+ | --- | --- |
24
+ | Use protocol models, validation, identity, and assertions | `agent_enrollment_protocol.core` |
25
+ | Inspect, enroll with, and authenticate to Services | `agent_enrollment_protocol.agent` |
26
+ | Integrate enrollment and authentication into a Service | `agent_enrollment_protocol.service` |
27
+ | Host managed Agent identities and delegated signing | `agent_enrollment_protocol.platform` |
28
+
29
+ Core is synchronous and transport-independent. Agent, Service, Platform, and their integration
30
+ interfaces are asynchronous. Applications provide durable stores and security policy through typed
31
+ protocols.
32
+
33
+ Framework integrations are optional and remain separate from Core and role behavior.
34
+
35
+ ## Runnable examples
36
+
37
+ The repository includes self-contained examples that exercise real signed protocol flows without
38
+ external infrastructure:
39
+
40
+ ```sh
41
+ uv run python examples/agent_service.py
42
+ uv run python examples/hosted_platform.py
43
+ ```
44
+
45
+ The first example composes an Agent, Service, every built-in credential profile, protected resource,
46
+ and the framework-neutral ASGI adapter. The second demonstrates hosted identity Platform discovery,
47
+ Service DID resolution, provisioning, DID publication, delegated signing, and identity listing. See
48
+ [`examples/README.md`](./examples/README.md) for the integration boundaries and production
49
+ replacements.
50
+
51
+ The Service module includes stored credential profiles for each built-in Grant Type:
52
+
53
+ | Grant Type | Factory |
54
+ | --- | --- |
55
+ | API key | `stored_api_key_grant_type()` |
56
+ | Basic | `stored_basic_grant_type()` |
57
+ | OAuth Bearer | `stored_oauth_bearer_grant_type()` |
58
+
59
+ Each factory accepts application-owned credential issuance and storage implementations. The included
60
+ memory store is intended for examples and local development.
61
+
62
+ Concrete Grant Types and extensions can define additional Grant and Revoke request members. Pass
63
+ those members through `GrantOptions.parameters` or `RevokeOptions.parameters`; the Agent retains
64
+ control of the standard Grant Type and Revoke selector fields.
65
+
66
+ ## Service ASGI integration
67
+
68
+ `agent_enrollment_protocol.adapters` provides a framework-neutral ASGI integration with no
69
+ additional dependency. `AepAsgiApplication` serves Inspect and every command advertised by the
70
+ Service. It enforces the command methods, media type, request-body limit, and idempotency header
71
+ boundary, and supplies cache metadata and conditional requests for Inspect.
72
+
73
+ `AepAuthenticationMiddleware` protects a downstream ASGI application and exposes the authenticated
74
+ Agent principal through `principal_from_scope()`. Place the protocol application outside the
75
+ authentication middleware so AEP's own command routes remain directly accessible:
76
+
77
+ ```python
78
+ from agent_enrollment_protocol.adapters import (
79
+ AepAsgiApplication,
80
+ AepAuthenticationMiddleware,
81
+ principal_from_scope,
82
+ )
83
+
84
+ protected_application = AepAuthenticationMiddleware(
85
+ application,
86
+ service,
87
+ resource_origin="https://service.example",
88
+ )
89
+ asgi_application = AepAsgiApplication(service, protected_application)
90
+ ```
91
+
92
+ The downstream application can obtain its immutable principal from the ASGI scope:
93
+
94
+ ```python
95
+ principal = principal_from_scope(scope)
96
+ if principal is None:
97
+ raise RuntimeError("The route requires AEP authentication")
98
+ ```
99
+
100
+ Use a separate unprotected application branch for public resources. For local development,
101
+ `allow_insecure_loopback=True` permits an HTTP `localhost` or loopback resource origin; production
102
+ origins require HTTPS.
103
+
104
+ ## Agent with a hosted identity Platform
105
+
106
+ `PlatformIdentityProvider` lets an Agent use a remote AEP Platform for Service-scoped identity
107
+ custody and delegated assertion signing. It discovers the Platform, recovers an existing active
108
+ identity before provisioning one, caches discovery metadata according to HTTP cache directives,
109
+ and supplies the resulting signer directly to `Agent`.
110
+
111
+ ```python
112
+ import os
113
+
114
+ from agent_enrollment_protocol.agent import (
115
+ Agent,
116
+ AgentOptions,
117
+ PlatformIdentityProvider,
118
+ PlatformIdentityProviderOptions,
119
+ )
120
+
121
+
122
+ async def authentication_headers() -> dict[str, str]:
123
+ return {"Authorization": f"Bearer {os.environ['AEP_PLATFORM_ACCESS_TOKEN']}"}
124
+
125
+
126
+ async with PlatformIdentityProvider(
127
+ PlatformIdentityProviderOptions(
128
+ authentication_headers=authentication_headers,
129
+ platform_url="https://platform.example",
130
+ )
131
+ ) as identities:
132
+ async with Agent(AgentOptions(identity_provider=identities)) as agent:
133
+ result = await agent.service("https://service.example").enroll()
134
+ ```
135
+
136
+ The Platform authentication callback is evaluated for each private request so applications can
137
+ refresh short-lived credentials. Supply `pending_sign_resolver` when the Platform can return
138
+ `202 Accepted` during delegated signing. The resolver receives the immutable retry interval and
139
+ opaque Platform context; returning updated context starts the next signing stage with a distinct
140
+ idempotency key. Without a resolver, pending signing raises `PlatformSignPendingError` for the
141
+ application to continue explicitly.
142
+
143
+ ## Hosted identity Platform
144
+
145
+ `agent_enrollment_protocol.platform` implements discovery, Service-scoped Agent identity
146
+ provisioning, DID document publication, identity listing and lifecycle, delegated signing, and
147
+ optional hosted verification.
148
+
149
+ Applications supply caller authorization, Service DID resolution, key custody, and durable stores.
150
+ The included memory stores are suitable for local development, not production key custody or
151
+ durable idempotency.
152
+
153
+ ```python
154
+ from datetime import timedelta
155
+
156
+ from agent_enrollment_protocol.core import SigningAlgorithm
157
+ from agent_enrollment_protocol.platform import DiscoveryOptions, Platform, PlatformOptions
158
+
159
+ platform = Platform(
160
+ PlatformOptions(
161
+ authorizer=authorizer,
162
+ did_host="platform.example",
163
+ did_url_template="https://platform.example/agents/{agent_did_id}/did.json",
164
+ discovery=DiscoveryOptions(
165
+ endpoint_base="/v1/aep",
166
+ lifecycle_endpoint="/v1/aep/agent-identities/{agent_identity_id}",
167
+ list_endpoint="/v1/aep/agent-identities",
168
+ platform_name="Example Platform",
169
+ provision_endpoint="/v1/aep/agent-identities",
170
+ sign_endpoint="/v1/aep/agent-identities/{agent_identity_id}/sign",
171
+ ),
172
+ key_store=key_store,
173
+ maximum_lifetime=timedelta(minutes=5),
174
+ service_did_resolver=service_did_resolver,
175
+ signing_algorithms=(SigningAlgorithm.ES256,),
176
+ )
177
+ )
178
+ ```
179
+
180
+ Map `platform.discovery()` to `/.well-known/aep-platform` and the remaining methods to the paths
181
+ advertised by `DiscoveryOptions`. Authenticate private Platform routes before constructing their
182
+ `RequestContext`; the Platform also invokes the supplied authorizer for every private operation.
183
+ Enable hosted verification only with a replay store.
184
+
185
+ ## Development
186
+
187
+ Install the locked development environment and run the complete merge gate:
188
+
189
+ ```sh
190
+ uv sync --all-groups --locked
191
+ make verify
192
+ ```
193
+
194
+ Run the shared Agent, Service, and Platform conformance suites against the public Python APIs:
195
+
196
+ ```sh
197
+ make conformance
198
+ ```
199
+
200
+ The command reads the adjacent `../aep-specs` checkout by default and writes role reports to
201
+ `.conformance/reports/`. Set `AEP_SPECS_DIR` when the specifications are checked out elsewhere.
202
+
203
+ Run bidirectional Agent, Service, and Platform interoperability against the Node.js SDK:
204
+
205
+ ```sh
206
+ make interoperability
207
+ ```
208
+
209
+ The command reads the adjacent `../aep-node` checkout by default and writes a four-row evidence
210
+ report to `.interop/reports/aep-python-node-interoperability.json`. Set `AEP_NODE_DIR` when the
211
+ Node.js SDK is checked out elsewhere.
212
+
213
+ See [`aep-specs`](https://github.com/aep-foundation/aep-specs) for the normative drafts, schemas,
214
+ registries, examples, and test vectors.
215
+
216
+ ## Releases
217
+
218
+ Maintainers run the `Release` workflow from `main`. It verifies the package and a clean consumer,
219
+ runs shared conformance and Node.js interoperability, publishes through PyPI Trusted Publishing,
220
+ attests the distributions, and creates the matching tag and GitHub release with the verification
221
+ reports.
222
+
223
+ ## Security
224
+
225
+ See [SECURITY.md](./SECURITY.md) for vulnerability reporting.
226
+
227
+ ## License
228
+
229
+ MIT.
@@ -0,0 +1,31 @@
1
+ # Examples
2
+
3
+ These examples run locally without external infrastructure. They use real signed assertions and the
4
+ public software development kit interfaces, while keeping identities, enrollments, credentials, and
5
+ keys in memory.
6
+
7
+ | Example | Demonstrates |
8
+ | --- | --- |
9
+ | [`agent_service.py`](./agent_service.py) | Agent inspection, enrollment, API-key, Basic, and OAuth Bearer grants, authenticated Service access, credential revocation, and rejected reuse through the ASGI adapter |
10
+ | [`hosted_platform.py`](./hosted_platform.py) | Hosted identity Platform discovery, Service DID resolution, provisioning, DID document publication, delegated signing, identity listing, and lifecycle management |
11
+
12
+ Run them from the repository root after installing the development environment:
13
+
14
+ ```sh
15
+ uv sync --all-groups --locked
16
+ uv run python examples/agent_service.py
17
+ uv run python examples/hosted_platform.py
18
+ ```
19
+
20
+ Both examples resolve `did:web` documents through HTTP clients using HTTPS URLs. Their in-memory
21
+ transports make the examples deterministic without bypassing DID resolution. Production
22
+ integrations use a normal HTTP client with their cache and network policy. Replace all memory stores
23
+ with durable implementations before deployment.
24
+
25
+ The Agent and Service example runs every built-in credential profile. Each profile supplies an issuer
26
+ callback and the same `ServiceCredentialStore` to its corresponding `stored_*_grant_type()` factory.
27
+ The example authenticates with each issued credential, revokes it, and confirms that reuse is rejected.
28
+
29
+ The Platform example deliberately keeps its private key in process. A production Platform supplies a
30
+ `KeyStore` backed by its key-management system and maps the Platform methods to authenticated HTTP
31
+ routes.