authsec-sdk 4.0.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.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ recursive-include src/authsec_sdk/spiffe_workload_api/api *.proto
3
+ global-exclude __pycache__ *.py[cod] .DS_Store
@@ -0,0 +1,415 @@
1
+ Metadata-Version: 2.4
2
+ Name: authsec-sdk
3
+ Version: 4.0.0
4
+ Summary: AuthSec SDK for MCP auth, services, CIBA, and SPIFFE integration
5
+ Author-email: AuthSec Team <a@authnull.com>
6
+ Keywords: authsec,mcp,oauth,rbac,spiffe,ciba,authentication,authorization
7
+ Requires-Python: >=3.10.11
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: aiohttp>=3.9.0
10
+ Requires-Dist: fastapi>=0.110.0
11
+ Requires-Dist: grpcio>=1.60.0
12
+ Requires-Dist: protobuf<6.0.0,>=5.29.0
13
+ Requires-Dist: requests>=2.31.0
14
+ Requires-Dist: uvicorn>=0.27.0
15
+
16
+ # AuthSec Python SDK (`authsec_sdk`)
17
+
18
+ Add OAuth + RBAC protection to MCP tools with minimal code changes.
19
+
20
+ This SDK lets you:
21
+ - Protect MCP tools with `@protected_by_AuthSec(...)`
22
+ - Register normal unprotected MCP tools with `@mcp_tool(...)`
23
+ - Run an MCP server that delegates auth/tool listing to AuthSec SDK Manager
24
+ - Access downstream service credentials safely through `ServiceAccessSDK`
25
+
26
+ ## What This SDK Does (and Why)
27
+
28
+ AuthSec is the **control plane**: users authenticate through AuthSec, show up in the AuthSec web app, and you assign them roles/permissions and conditional access policies.
29
+
30
+ This Python package is the **enforcement layer for MCP**:
31
+ - It provides a minimal HTTP MCP server (`run_mcp_server_with_oauth(...)`) so you do not need to implement MCP transport + OAuth bootstrap tools yourself.
32
+ - It delegates OAuth flows and authorization decisions to the hosted AuthSec SDK Manager.
33
+ - It enforces allow/deny for protected tools at **call time** (the security boundary), and can also hide tools in `tools/list` as a UX improvement (policy controlled by AuthSec).
34
+
35
+ Why this approach:
36
+ - B2B teams often have many internal tools. You configure identity + RBAC once in AuthSec, then every MCP tool can inherit the same enterprise policy without re-implementing Okta/SAML/SCIM in each server.
37
+ - The SDK stays thin: your business logic stays in your tool handlers; AuthSec decides who can call them.
38
+
39
+ ## Package
40
+
41
+ - Name: `authsec-sdk`
42
+ - Import path: `authsec_sdk`
43
+ - Python: `>=3.10.11`
44
+
45
+ ## Install
46
+
47
+ ### One command on macOS
48
+
49
+ From the repo:
50
+
51
+ ```bash
52
+ bash scripts/bootstrap-python-sdk-macos.sh --client-id YOUR_CLIENT_ID
53
+ ```
54
+
55
+ Using GitHub raw:
56
+
57
+ ```bash
58
+ curl -fsSL https://raw.githubusercontent.com/authsec-ai/sdk-authsec/main/scripts/bootstrap-python-sdk-macos.sh | bash -s -- --client-id YOUR_CLIENT_ID
59
+ ```
60
+
61
+ Notes:
62
+ - Default install source is `pypi`.
63
+ - Use `--source https` or `--source ssh` if you want to install directly from GitHub.
64
+ - Add `--run` to start the sample server immediately after setup.
65
+
66
+ ### Local development
67
+
68
+ ```bash
69
+ cd packages/python-sdk
70
+ python3 -m pip install -e .
71
+ ```
72
+
73
+ ### From GitHub (advanced)
74
+
75
+ If you already cloned this repo, the shortest path is an editable install:
76
+
77
+ ```bash
78
+ python3 -m pip install -e packages/python-sdk
79
+ ```
80
+
81
+ If you need a one-command setup on macOS, use the bootstrap script above.
82
+
83
+ <details>
84
+ <summary>Direct pip install from GitHub monorepo (long command)</summary>
85
+
86
+ ```bash
87
+ python3 -m venv .venv
88
+ source .venv/bin/activate
89
+ python3 -m pip install --upgrade pip
90
+ python3 -m pip install "git+ssh://git@github.com/authsec-ai/sdk-authsec.git@main#subdirectory=packages/python-sdk"
91
+ ```
92
+
93
+ If you prefer HTTPS:
94
+
95
+ ```bash
96
+ python3 -m pip install "git+https://github.com/authsec-ai/sdk-authsec.git@main#subdirectory=packages/python-sdk"
97
+ ```
98
+
99
+ #### Windows PowerShell
100
+
101
+ ```powershell
102
+ py -3 -m venv .venv
103
+ .venv\Scripts\Activate.ps1
104
+ py -3 -m pip install --upgrade pip
105
+ py -3 -m pip install "git+https://github.com/authsec-ai/sdk-authsec.git@main#subdirectory=packages/python-sdk"
106
+ ```
107
+
108
+ If your org uses GitHub SSH on Windows:
109
+
110
+ ```powershell
111
+ py -3 -m pip install "git+ssh://git@github.com/authsec-ai/sdk-authsec.git@main#subdirectory=packages/python-sdk"
112
+ ```
113
+ </details>
114
+
115
+ ### From package index
116
+
117
+ ```bash
118
+ python3 -m pip install authsec-sdk
119
+ ```
120
+
121
+ #### Windows PowerShell
122
+
123
+ ```powershell
124
+ py -3 -m pip install authsec-sdk
125
+ ```
126
+
127
+ ### Verify install
128
+
129
+ #### macOS / Linux
130
+
131
+ ```bash
132
+ python3 -c "import authsec_sdk; print(authsec_sdk.__version__)"
133
+ ```
134
+
135
+ #### Windows PowerShell
136
+
137
+ ```powershell
138
+ py -3 -c "import authsec_sdk; print(authsec_sdk.__version__)"
139
+ ```
140
+
141
+ ## Quick Start
142
+
143
+ Create `server.py`:
144
+
145
+ ```python
146
+ from authsec_sdk import mcp_tool, protected_by_AuthSec, run_mcp_server_with_oauth
147
+
148
+
149
+ @mcp_tool(
150
+ name="ping",
151
+ description="Health check tool",
152
+ inputSchema={
153
+ "type": "object",
154
+ "properties": {},
155
+ "required": []
156
+ }
157
+ )
158
+ async def ping(arguments: dict) -> list:
159
+ return [{"type": "text", "text": "pong"}]
160
+
161
+
162
+ @protected_by_AuthSec(
163
+ tool_name="delete_invoice",
164
+ roles=["admin"],
165
+ scopes=["write"],
166
+ require_all=True,
167
+ description="Delete invoice by id",
168
+ inputSchema={
169
+ "type": "object",
170
+ "properties": {
171
+ "invoice_id": {"type": "string"},
172
+ "session_id": {"type": "string"}
173
+ },
174
+ "required": ["invoice_id"]
175
+ }
176
+ )
177
+ async def delete_invoice(arguments: dict) -> list:
178
+ invoice_id = arguments.get("invoice_id")
179
+ user = (arguments.get("_user_info") or {}).get("email_id", "unknown-user")
180
+ return [{"type": "text", "text": f"Deleted invoice {invoice_id} by {user}"}]
181
+
182
+
183
+ if __name__ == "__main__":
184
+ import __main__
185
+
186
+ run_mcp_server_with_oauth(
187
+ user_module=__main__,
188
+ client_id="YOUR_CLIENT_ID",
189
+ app_name="my-python-mcp",
190
+ host="127.0.0.1",
191
+ port=3005,
192
+ )
193
+ ```
194
+
195
+ Run on macOS / Linux:
196
+
197
+ ```bash
198
+ AUTHSEC_AUTH_SERVICE_URL="https://dev.api.authsec.dev/sdkmgr/mcp-auth" \
199
+ AUTHSEC_SERVICES_URL="https://dev.api.authsec.dev/sdkmgr/services" \
200
+ python3 server.py
201
+ ```
202
+
203
+ Run on Windows PowerShell:
204
+
205
+ ```powershell
206
+ $env:AUTHSEC_AUTH_SERVICE_URL = "https://dev.api.authsec.dev/sdkmgr/mcp-auth"
207
+ $env:AUTHSEC_SERVICES_URL = "https://dev.api.authsec.dev/sdkmgr/services"
208
+ py -3 .\server.py
209
+ ```
210
+
211
+ Connect MCP Inspector:
212
+
213
+ ```bash
214
+ npx @modelcontextprotocol/inspector http://127.0.0.1:3005
215
+ ```
216
+
217
+ ### Full setup by OS
218
+
219
+ #### macOS / Linux
220
+
221
+ 1. Create and activate a virtual environment.
222
+ 2. Install the SDK from GitHub or from a package index.
223
+ 3. Create `server.py` with `from authsec_sdk import ...`.
224
+ 4. Export `AUTHSEC_AUTH_SERVICE_URL` and `AUTHSEC_SERVICES_URL` if you want to override the defaults.
225
+ 5. Run `python3 server.py`.
226
+ 6. Open MCP Inspector against `http://127.0.0.1:3005`.
227
+
228
+ #### Windows PowerShell
229
+
230
+ 1. Create and activate a virtual environment with `py -3 -m venv .venv` and `.venv\Scripts\Activate.ps1`.
231
+ 2. Install the SDK from GitHub or from a package index.
232
+ 3. Create `server.py` with `from authsec_sdk import ...`.
233
+ 4. Set `$env:AUTHSEC_AUTH_SERVICE_URL` and `$env:AUTHSEC_SERVICES_URL` if you want to override the defaults.
234
+ 5. Run `py -3 .\server.py`.
235
+ 6. Open MCP Inspector against `http://127.0.0.1:3005`.
236
+
237
+ ## How Protection Works
238
+
239
+ 1. Server exposes OAuth tools from SDK Manager (`oauth_start`, `oauth_authenticate`, `oauth_status`, etc.).
240
+ 2. User authenticates and gets/uses a session.
241
+ 3. When a protected tool is called, SDK hits `protect-tool` upstream.
242
+ 4. RBAC is evaluated from your tool declaration (`roles`, `groups`, `resources`, `scopes`, `permissions`).
243
+ 5. On success, your handler receives:
244
+ - `arguments["session_id"]` (resolved session)
245
+ - `arguments["_user_info"]` (JWT/user claims)
246
+
247
+ Auth behavior note:
248
+ - Auth decisions are delegated upstream to SDK Manager.
249
+ - SDK may still expose OAuth tool schemas when upstream `tools/list` is unavailable so clients can continue auth bootstrap.
250
+
251
+ ## Decorators
252
+
253
+ ### `@protected_by_AuthSec(...)`
254
+
255
+ Use for tools that require auth/RBAC.
256
+
257
+ Key parameters:
258
+ - `tool_name`
259
+ - `roles`, `groups`, `resources`, `scopes`, `permissions`
260
+ - `require_all` (default `False`; if `True`, all specified categories must match)
261
+ - `description`
262
+ - `inputSchema`
263
+
264
+ ### `@mcp_tool(...)`
265
+
266
+ Use for tools that should stay unprotected.
267
+
268
+ Key parameters:
269
+ - `name`
270
+ - `description`
271
+ - `inputSchema`
272
+
273
+ ## Session-Aware Handler Pattern
274
+
275
+ If your protected function accepts a second `session` argument, SDK passes a simple session object:
276
+
277
+ ```python
278
+ @protected_by_AuthSec("service_call", scopes=["read"])
279
+ async def service_call(arguments: dict, session) -> list:
280
+ # session.session_id, session.user_id, session.tenant_id, session.access_token
281
+ return [{"type": "text", "text": session.session_id}]
282
+ ```
283
+
284
+ ## Service Access SDK
285
+
286
+ Use `ServiceAccessSDK(session)` to fetch service credentials/tokens from SDK Manager services API:
287
+
288
+ ```python
289
+ from authsec_sdk import ServiceAccessSDK
290
+
291
+ @protected_by_AuthSec("fetch_github_token", scopes=["read"])
292
+ async def fetch_github_token(arguments: dict, session) -> list:
293
+ services = ServiceAccessSDK(session)
294
+ token = await services.get_service_token("github")
295
+ return [{"type": "text", "text": f"Token length: {len(token)}"}]
296
+ ```
297
+
298
+ ## Environment Variables
299
+
300
+ SDK runtime:
301
+ - `AUTHSEC_AUTH_SERVICE_URL` (optional, default points to dev)
302
+ - `AUTHSEC_SERVICES_URL` (optional, default points to dev)
303
+ - `AUTHSEC_TIMEOUT_SECONDS` (default `15`)
304
+ - `AUTHSEC_RETRIES` (default `2`)
305
+ - `AUTHSEC_TOOLS_LIST_TIMEOUT_SECONDS` (default `8`)
306
+
307
+ Note:
308
+ - Tool visibility policies like `AUTHSEC_ALWAYS_EXPOSE_PROTECTED_TOOLS` / `AUTHSEC_HIDE_UNAUTHORIZED_TOOLS` are controlled in SDK Manager service config, not this package.
309
+
310
+ ## Troubleshooting
311
+
312
+ - `ModuleNotFoundError: No module named 'AuthSec_SDK'`
313
+ - The correct import is `from authsec_sdk import ...`. The package name is `authsec-sdk`, but the Python import path is `authsec_sdk`.
314
+ - Local folder named `authsec_sdk` shadows the installed package
315
+ - Rename or remove the local folder before running your app. `python path/to/script.py` puts that script directory first on `sys.path`.
316
+ - Apple Silicon Mac imports fail with `incompatible architecture`
317
+ - Do not mix `arm64` and `x86_64` Python environments. Recreate the virtualenv using the same architecture you will run.
318
+ - `OAuth tool failed: ... released back to the pool`
319
+ - This is an SDK Manager backend deployment/version issue, not client SDK usage.
320
+ - `verifyToken failed: 404`
321
+ - Check SDK Manager `AUTH_MANAGER_URL` and ensure it targets your correct environment (`dev` vs `prod`).
322
+ - Protected tools denied unexpectedly
323
+ - Confirm JWT claims contain expected roles/scopes/resources and match your decorator RBAC.
324
+
325
+ ## Prompt Template (Copy/Paste)
326
+
327
+ Use this prompt with any coding LLM to wrap a Python MCP server with AuthSec:
328
+
329
+ ```text
330
+ You are editing a Python MCP server codebase.
331
+
332
+ Goal:
333
+ 1) Integrate authsec_sdk so selected tools are protected with OAuth + RBAC.
334
+ 2) Keep public tools unprotected.
335
+ 3) Start server via run_mcp_server_with_oauth.
336
+
337
+ Requirements:
338
+ - Use @protected_by_AuthSec for sensitive tools.
339
+ - Use @mcp_tool for unprotected tools.
340
+ - Pass a clear inputSchema for each tool.
341
+ - Ensure protected handlers read user info from arguments["_user_info"].
342
+ - Keep all OAuth/auth checks delegated upstream (no local bypass/fallback logic).
343
+ - Add startup instructions using AUTHSEC_AUTH_SERVICE_URL and AUTHSEC_SERVICES_URL.
344
+
345
+ Inputs:
346
+ - client_id: <YOUR_CLIENT_ID>
347
+ - app_name: <YOUR_APP_NAME>
348
+ - protected tools + RBAC:
349
+ - <tool_name_1>: roles=[...], scopes=[...], require_all=<true/false>
350
+ - <tool_name_2>: ...
351
+ - unprotected tools:
352
+ - <tool_name_3>
353
+
354
+ Deliverables:
355
+ - Updated Python source files.
356
+ - A runnable command section.
357
+ - A short verification checklist using MCP Inspector.
358
+ ```
359
+
360
+ ## Publishing (Python)
361
+
362
+ ### One-command publish (recommended)
363
+
364
+ From the repo root:
365
+
366
+ ```bash
367
+ # TestPyPI first
368
+ bash scripts/publish-python-sdk.sh --test
369
+
370
+ # Then PyPI
371
+ bash scripts/publish-python-sdk.sh
372
+ ```
373
+
374
+ Auth for `twine` (do not commit tokens):
375
+
376
+ ```bash
377
+ export TWINE_USERNAME="__token__"
378
+ export TWINE_PASSWORD="pypi-REDACTED"
379
+ ```
380
+
381
+ ### 1) Bump version
382
+
383
+ Update version consistently:
384
+ - `packages/python-sdk/pyproject.toml` -> `[project].version`
385
+ - `packages/python-sdk/src/authsec_sdk/__init__.py` -> `__version__`
386
+
387
+ ### 2) Build artifacts
388
+
389
+ ```bash
390
+ cd packages/python-sdk
391
+ python3 -m pip install --upgrade build twine
392
+ python3 -m build
393
+ python3 -m twine check dist/*
394
+ ```
395
+
396
+ ### 3) Test publish (recommended)
397
+
398
+ ```bash
399
+ python3 -m twine upload --repository testpypi dist/*
400
+ ```
401
+
402
+ Install from TestPyPI in a clean venv and run smoke test.
403
+
404
+ ### 4) Publish to PyPI
405
+
406
+ ```bash
407
+ python3 -m twine upload dist/*
408
+ ```
409
+
410
+ ### 5) Post-publish check
411
+
412
+ ```bash
413
+ python3 -m pip install --upgrade authsec-sdk
414
+ python3 -c "import authsec_sdk; print(authsec_sdk.__version__)"
415
+ ```