langchain-nuggets 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 (51) hide show
  1. langchain_nuggets-0.1.0/.gitignore +17 -0
  2. langchain_nuggets-0.1.0/PKG-INFO +196 -0
  3. langchain_nuggets-0.1.0/README.md +172 -0
  4. langchain_nuggets-0.1.0/langchain_nuggets/__init__.py +77 -0
  5. langchain_nuggets-0.1.0/langchain_nuggets/client/__init__.py +3 -0
  6. langchain_nuggets-0.1.0/langchain_nuggets/client/nuggets_api_client.py +192 -0
  7. langchain_nuggets-0.1.0/langchain_nuggets/langgraph/__init__.py +25 -0
  8. langchain_nuggets-0.1.0/langchain_nuggets/langgraph/auth.py +155 -0
  9. langchain_nuggets-0.1.0/langchain_nuggets/langgraph/authorization.py +110 -0
  10. langchain_nuggets-0.1.0/langchain_nuggets/langgraph/token_verifier.py +207 -0
  11. langchain_nuggets-0.1.0/langchain_nuggets/langgraph/types.py +31 -0
  12. langchain_nuggets-0.1.0/langchain_nuggets/middleware/__init__.py +24 -0
  13. langchain_nuggets-0.1.0/langchain_nuggets/middleware/authority_middleware.py +266 -0
  14. langchain_nuggets-0.1.0/langchain_nuggets/middleware/proof.py +65 -0
  15. langchain_nuggets-0.1.0/langchain_nuggets/middleware/types.py +76 -0
  16. langchain_nuggets-0.1.0/langchain_nuggets/toolkit.py +80 -0
  17. langchain_nuggets-0.1.0/langchain_nuggets/tools/__init__.py +3 -0
  18. langchain_nuggets-0.1.0/langchain_nuggets/tools/auth/__init__.py +14 -0
  19. langchain_nuggets-0.1.0/langchain_nuggets/tools/auth/check_auth_status.py +29 -0
  20. langchain_nuggets-0.1.0/langchain_nuggets/tools/auth/initiate_oauth_flow.py +29 -0
  21. langchain_nuggets-0.1.0/langchain_nuggets/tools/auth/request_credential_presentation.py +29 -0
  22. langchain_nuggets-0.1.0/langchain_nuggets/tools/auth/verify_presentation.py +29 -0
  23. langchain_nuggets-0.1.0/langchain_nuggets/tools/base.py +29 -0
  24. langchain_nuggets-0.1.0/langchain_nuggets/tools/kya/__init__.py +10 -0
  25. langchain_nuggets-0.1.0/langchain_nuggets/tools/kya/get_agent_trust_score.py +29 -0
  26. langchain_nuggets-0.1.0/langchain_nuggets/tools/kya/register_agent_identity.py +40 -0
  27. langchain_nuggets-0.1.0/langchain_nuggets/tools/kya/verify_agent_identity.py +29 -0
  28. langchain_nuggets-0.1.0/langchain_nuggets/tools/kyc/__init__.py +12 -0
  29. langchain_nuggets-0.1.0/langchain_nuggets/tools/kyc/check_kyc_status.py +29 -0
  30. langchain_nuggets-0.1.0/langchain_nuggets/tools/kyc/initiate_kyc_verification.py +28 -0
  31. langchain_nuggets-0.1.0/langchain_nuggets/tools/kyc/verify_age.py +29 -0
  32. langchain_nuggets-0.1.0/langchain_nuggets/tools/kyc/verify_credential.py +29 -0
  33. langchain_nuggets-0.1.0/langchain_nuggets/types.py +103 -0
  34. langchain_nuggets-0.1.0/pyproject.toml +54 -0
  35. langchain_nuggets-0.1.0/tests/__init__.py +1 -0
  36. langchain_nuggets-0.1.0/tests/conftest.py +14 -0
  37. langchain_nuggets-0.1.0/tests/langgraph/__init__.py +0 -0
  38. langchain_nuggets-0.1.0/tests/langgraph/test_auth.py +139 -0
  39. langchain_nuggets-0.1.0/tests/langgraph/test_authorization.py +84 -0
  40. langchain_nuggets-0.1.0/tests/langgraph/test_token_verifier.py +231 -0
  41. langchain_nuggets-0.1.0/tests/middleware/__init__.py +0 -0
  42. langchain_nuggets-0.1.0/tests/middleware/test_authority_middleware.py +452 -0
  43. langchain_nuggets-0.1.0/tests/middleware/test_proof.py +172 -0
  44. langchain_nuggets-0.1.0/tests/middleware/test_types.py +164 -0
  45. langchain_nuggets-0.1.0/tests/test_nuggets_api_client.py +114 -0
  46. langchain_nuggets-0.1.0/tests/test_toolkit.py +73 -0
  47. langchain_nuggets-0.1.0/tests/tools/__init__.py +1 -0
  48. langchain_nuggets-0.1.0/tests/tools/test_auth.py +154 -0
  49. langchain_nuggets-0.1.0/tests/tools/test_base.py +41 -0
  50. langchain_nuggets-0.1.0/tests/tools/test_kya.py +101 -0
  51. langchain_nuggets-0.1.0/tests/tools/test_kyc.py +131 -0
@@ -0,0 +1,17 @@
1
+ node_modules/
2
+ dist/
3
+ .turbo/
4
+ *.tsbuildinfo
5
+ .env
6
+ .env.local
7
+
8
+ # Python
9
+ __pycache__/
10
+ *.py[cod]
11
+ *.egg-info/
12
+ *.egg
13
+ dist/
14
+ build/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .pytest_cache/
@@ -0,0 +1,196 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-nuggets
3
+ Version: 0.1.0
4
+ Summary: Nuggets identity verification toolkit for LangChain Python
5
+ Project-URL: Repository, https://github.com/NuggetsLtd/langchain-nuggets
6
+ License-Expression: MIT
7
+ Keywords: ai,identity,kyc,langchain,nuggets,tools,verification
8
+ Requires-Python: >=3.9
9
+ Requires-Dist: httpx>=0.27.0
10
+ Requires-Dist: langchain-core>=0.3.0
11
+ Requires-Dist: pydantic>=2.0.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: langgraph-sdk>=0.1.0; extra == 'dev'
14
+ Requires-Dist: mypy>=1.13.0; extra == 'dev'
15
+ Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'dev'
16
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
17
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
18
+ Requires-Dist: respx>=0.22.0; extra == 'dev'
19
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
20
+ Provides-Extra: langgraph
21
+ Requires-Dist: langgraph-sdk>=0.1.0; extra == 'langgraph'
22
+ Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'langgraph'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # langchain-nuggets
26
+
27
+ Nuggets identity verification toolkit for LangChain Python. Provides 11 ready-to-use tools for KYC, KYA, and credential verification that plug directly into any LangChain agent.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install langchain-nuggets
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ```python
38
+ from langchain_nuggets import NuggetsToolkit
39
+
40
+ # Config via env vars: NUGGETS_API_URL, NUGGETS_PARTNER_ID, NUGGETS_PARTNER_SECRET
41
+ toolkit = NuggetsToolkit()
42
+ tools = toolkit.get_tools()
43
+
44
+ # Or pass config directly
45
+ toolkit = NuggetsToolkit(
46
+ api_url="https://api.nuggets.life",
47
+ partner_id="your-partner-id",
48
+ partner_secret="your-secret",
49
+ )
50
+ ```
51
+
52
+ ## Tools
53
+
54
+ ### KYC (Know Your Customer)
55
+
56
+ | Tool | Description |
57
+ |------|-------------|
58
+ | `initiate_kyc_verification` | Start identity verification flow, returns deeplink/QR for Nuggets app |
59
+ | `check_kyc_status` | Poll verification session status (pending/completed/failed/expired) |
60
+ | `verify_age` | Selective disclosure age proof without revealing date of birth |
61
+ | `verify_credential` | Request specific credential (address, email, phone, nationality) |
62
+
63
+ ### KYA (Know Your Agent)
64
+
65
+ | Tool | Description |
66
+ |------|-------------|
67
+ | `register_agent_identity` | Register AI agent identity with DID and provenance signals |
68
+ | `verify_agent_identity` | Verify another agent's identity and provenance |
69
+ | `get_agent_trust_score` | Get trust score (0-1) based on verified signals |
70
+
71
+ ### Auth & Credentials
72
+
73
+ | Tool | Description |
74
+ |------|-------------|
75
+ | `request_credential_presentation` | Ask user to present verifiable credentials |
76
+ | `verify_presentation` | Check presentation status and verify credentials |
77
+ | `initiate_oauth_flow` | Start OAuth 2.0/OIDC flow with Nuggets as IdP |
78
+ | `check_auth_status` | Check user's authentication and verification status |
79
+
80
+ ## Usage with LangChain Agent
81
+
82
+ ```python
83
+ from langchain_openai import ChatOpenAI
84
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
85
+ from langchain_core.prompts import ChatPromptTemplate
86
+ from langchain_nuggets import NuggetsToolkit
87
+
88
+ toolkit = NuggetsToolkit()
89
+ tools = toolkit.get_tools()
90
+
91
+ llm = ChatOpenAI(model="gpt-4o", temperature=0)
92
+ prompt = ChatPromptTemplate.from_messages([
93
+ ("system", "You are a helpful assistant that can verify user identities using Nuggets."),
94
+ ("human", "{input}"),
95
+ ("placeholder", "{agent_scratchpad}"),
96
+ ])
97
+
98
+ agent = create_openai_tools_agent(llm, tools, prompt)
99
+ executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
100
+
101
+ result = executor.invoke({"input": "Verify alice@example.com"})
102
+ ```
103
+
104
+ ## Configuration
105
+
106
+ | Parameter | Env Variable | Description |
107
+ |-----------|-------------|-------------|
108
+ | `api_url` | `NUGGETS_API_URL` | Nuggets API base URL |
109
+ | `partner_id` | `NUGGETS_PARTNER_ID` | Your partner ID |
110
+ | `partner_secret` | `NUGGETS_PARTNER_SECRET` | Your partner secret |
111
+
112
+
113
+ ## Self-Hosted Deployment
114
+
115
+ All classes accept configurable URLs — point to your own Nuggets instance:
116
+
117
+ ```python
118
+ toolkit = NuggetsToolkit(
119
+ api_url="https://nuggets.internal.example.com/api",
120
+ partner_id="your-partner-id",
121
+ partner_secret="your-secret",
122
+ )
123
+ ```
124
+
125
+ ### Custom CA Certificates
126
+
127
+ For self-hosted instances using a private CA:
128
+
129
+ ```python
130
+ toolkit = NuggetsToolkit(
131
+ api_url="https://nuggets.internal.example.com/api",
132
+ partner_id="your-partner-id",
133
+ partner_secret="your-secret",
134
+ ca_cert="/etc/ssl/private-ca/nuggets-ca.pem",
135
+ )
136
+ ```
137
+
138
+ The `ca_cert` and `verify_ssl` parameters are also available on:
139
+ - `NuggetsAuth(issuer_url=..., ca_cert=..., verify_ssl=...)`
140
+ - `MiddlewareConfig(api_url=..., ca_cert=..., verify_ssl=...)`
141
+ - `NuggetsApiClient({"api_url": ..., "ca_cert": ..., "verify_ssl": ...})`
142
+
143
+ To disable TLS verification entirely (development/staging only):
144
+
145
+ ```python
146
+ toolkit = NuggetsToolkit(..., verify_ssl=False)
147
+ ```
148
+
149
+ ## License
150
+
151
+ MIT
152
+
153
+ ## Authority Middleware
154
+
155
+ Intercept every LangChain/LangGraph tool call with pre-execution trust enforcement. The middleware validates authority against the Nuggets control plane, blocks unauthorized actions, and emits cryptographic proof artifacts.
156
+
157
+ ```python
158
+ from langchain_nuggets.middleware import NuggetsAuthorityMiddleware, MiddlewareConfig
159
+ from langgraph.prebuilt import ToolNode
160
+
161
+ config = MiddlewareConfig(
162
+ api_url="https://api.nuggets.life",
163
+ partner_id="your-partner-id",
164
+ partner_secret="your-secret",
165
+ agent_id="agent-001",
166
+ controller_id="org-001",
167
+ delegation_id="del-001",
168
+ )
169
+
170
+ middleware = NuggetsAuthorityMiddleware(config)
171
+
172
+ tool_node = ToolNode(
173
+ tools=your_tools,
174
+ wrap_tool_call=middleware.wrap_tool_call, # sync
175
+ # awrap_tool_call=middleware.awrap_tool_call, # async
176
+ )
177
+ ```
178
+
179
+ **Execution model:** `Agent → Tool Call → Nuggets Authority Check → Allow/Deny → Emit Proof`
180
+
181
+ **Trust primitives enforced:** Actor Identity, Authority (delegation), Policy, Intent, Consent, Accountability (provenance).
182
+
183
+ | Behaviour | Detail |
184
+ |-----------|--------|
185
+ | **ALLOW** | Tool executes, proof artifact emitted |
186
+ | **DENY** | Tool blocked, structured error returned |
187
+ | **ERROR** | Fail closed — tool not executed |
188
+
189
+ Access proof artifacts after execution:
190
+
191
+ ```python
192
+ for proof in middleware.proofs:
193
+ print(f"{proof.proof_id}: {proof.tool} latency={proof.latency_ms:.0f}ms")
194
+ ```
195
+
196
+ See the [demo script](../../examples/python/authority_middleware_demo.py) for a complete working example.
@@ -0,0 +1,172 @@
1
+ # langchain-nuggets
2
+
3
+ Nuggets identity verification toolkit for LangChain Python. Provides 11 ready-to-use tools for KYC, KYA, and credential verification that plug directly into any LangChain agent.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install langchain-nuggets
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from langchain_nuggets import NuggetsToolkit
15
+
16
+ # Config via env vars: NUGGETS_API_URL, NUGGETS_PARTNER_ID, NUGGETS_PARTNER_SECRET
17
+ toolkit = NuggetsToolkit()
18
+ tools = toolkit.get_tools()
19
+
20
+ # Or pass config directly
21
+ toolkit = NuggetsToolkit(
22
+ api_url="https://api.nuggets.life",
23
+ partner_id="your-partner-id",
24
+ partner_secret="your-secret",
25
+ )
26
+ ```
27
+
28
+ ## Tools
29
+
30
+ ### KYC (Know Your Customer)
31
+
32
+ | Tool | Description |
33
+ |------|-------------|
34
+ | `initiate_kyc_verification` | Start identity verification flow, returns deeplink/QR for Nuggets app |
35
+ | `check_kyc_status` | Poll verification session status (pending/completed/failed/expired) |
36
+ | `verify_age` | Selective disclosure age proof without revealing date of birth |
37
+ | `verify_credential` | Request specific credential (address, email, phone, nationality) |
38
+
39
+ ### KYA (Know Your Agent)
40
+
41
+ | Tool | Description |
42
+ |------|-------------|
43
+ | `register_agent_identity` | Register AI agent identity with DID and provenance signals |
44
+ | `verify_agent_identity` | Verify another agent's identity and provenance |
45
+ | `get_agent_trust_score` | Get trust score (0-1) based on verified signals |
46
+
47
+ ### Auth & Credentials
48
+
49
+ | Tool | Description |
50
+ |------|-------------|
51
+ | `request_credential_presentation` | Ask user to present verifiable credentials |
52
+ | `verify_presentation` | Check presentation status and verify credentials |
53
+ | `initiate_oauth_flow` | Start OAuth 2.0/OIDC flow with Nuggets as IdP |
54
+ | `check_auth_status` | Check user's authentication and verification status |
55
+
56
+ ## Usage with LangChain Agent
57
+
58
+ ```python
59
+ from langchain_openai import ChatOpenAI
60
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
61
+ from langchain_core.prompts import ChatPromptTemplate
62
+ from langchain_nuggets import NuggetsToolkit
63
+
64
+ toolkit = NuggetsToolkit()
65
+ tools = toolkit.get_tools()
66
+
67
+ llm = ChatOpenAI(model="gpt-4o", temperature=0)
68
+ prompt = ChatPromptTemplate.from_messages([
69
+ ("system", "You are a helpful assistant that can verify user identities using Nuggets."),
70
+ ("human", "{input}"),
71
+ ("placeholder", "{agent_scratchpad}"),
72
+ ])
73
+
74
+ agent = create_openai_tools_agent(llm, tools, prompt)
75
+ executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
76
+
77
+ result = executor.invoke({"input": "Verify alice@example.com"})
78
+ ```
79
+
80
+ ## Configuration
81
+
82
+ | Parameter | Env Variable | Description |
83
+ |-----------|-------------|-------------|
84
+ | `api_url` | `NUGGETS_API_URL` | Nuggets API base URL |
85
+ | `partner_id` | `NUGGETS_PARTNER_ID` | Your partner ID |
86
+ | `partner_secret` | `NUGGETS_PARTNER_SECRET` | Your partner secret |
87
+
88
+
89
+ ## Self-Hosted Deployment
90
+
91
+ All classes accept configurable URLs — point to your own Nuggets instance:
92
+
93
+ ```python
94
+ toolkit = NuggetsToolkit(
95
+ api_url="https://nuggets.internal.example.com/api",
96
+ partner_id="your-partner-id",
97
+ partner_secret="your-secret",
98
+ )
99
+ ```
100
+
101
+ ### Custom CA Certificates
102
+
103
+ For self-hosted instances using a private CA:
104
+
105
+ ```python
106
+ toolkit = NuggetsToolkit(
107
+ api_url="https://nuggets.internal.example.com/api",
108
+ partner_id="your-partner-id",
109
+ partner_secret="your-secret",
110
+ ca_cert="/etc/ssl/private-ca/nuggets-ca.pem",
111
+ )
112
+ ```
113
+
114
+ The `ca_cert` and `verify_ssl` parameters are also available on:
115
+ - `NuggetsAuth(issuer_url=..., ca_cert=..., verify_ssl=...)`
116
+ - `MiddlewareConfig(api_url=..., ca_cert=..., verify_ssl=...)`
117
+ - `NuggetsApiClient({"api_url": ..., "ca_cert": ..., "verify_ssl": ...})`
118
+
119
+ To disable TLS verification entirely (development/staging only):
120
+
121
+ ```python
122
+ toolkit = NuggetsToolkit(..., verify_ssl=False)
123
+ ```
124
+
125
+ ## License
126
+
127
+ MIT
128
+
129
+ ## Authority Middleware
130
+
131
+ Intercept every LangChain/LangGraph tool call with pre-execution trust enforcement. The middleware validates authority against the Nuggets control plane, blocks unauthorized actions, and emits cryptographic proof artifacts.
132
+
133
+ ```python
134
+ from langchain_nuggets.middleware import NuggetsAuthorityMiddleware, MiddlewareConfig
135
+ from langgraph.prebuilt import ToolNode
136
+
137
+ config = MiddlewareConfig(
138
+ api_url="https://api.nuggets.life",
139
+ partner_id="your-partner-id",
140
+ partner_secret="your-secret",
141
+ agent_id="agent-001",
142
+ controller_id="org-001",
143
+ delegation_id="del-001",
144
+ )
145
+
146
+ middleware = NuggetsAuthorityMiddleware(config)
147
+
148
+ tool_node = ToolNode(
149
+ tools=your_tools,
150
+ wrap_tool_call=middleware.wrap_tool_call, # sync
151
+ # awrap_tool_call=middleware.awrap_tool_call, # async
152
+ )
153
+ ```
154
+
155
+ **Execution model:** `Agent → Tool Call → Nuggets Authority Check → Allow/Deny → Emit Proof`
156
+
157
+ **Trust primitives enforced:** Actor Identity, Authority (delegation), Policy, Intent, Consent, Accountability (provenance).
158
+
159
+ | Behaviour | Detail |
160
+ |-----------|--------|
161
+ | **ALLOW** | Tool executes, proof artifact emitted |
162
+ | **DENY** | Tool blocked, structured error returned |
163
+ | **ERROR** | Fail closed — tool not executed |
164
+
165
+ Access proof artifacts after execution:
166
+
167
+ ```python
168
+ for proof in middleware.proofs:
169
+ print(f"{proof.proof_id}: {proof.tool} latency={proof.latency_ms:.0f}ms")
170
+ ```
171
+
172
+ See the [demo script](../../examples/python/authority_middleware_demo.py) for a complete working example.
@@ -0,0 +1,77 @@
1
+ """Nuggets identity verification toolkit for LangChain."""
2
+ from langchain_nuggets.client.nuggets_api_client import (
3
+ NuggetsApiClient,
4
+ NuggetsApiClientError,
5
+ )
6
+ from langchain_nuggets.toolkit import NuggetsToolkit
7
+
8
+ # Auth tools
9
+ from langchain_nuggets.tools.auth import (
10
+ CheckAuthStatus,
11
+ InitiateOAuthFlow,
12
+ RequestCredentialPresentation,
13
+ VerifyPresentation,
14
+ )
15
+ from langchain_nuggets.tools.base import NuggetsBaseTool
16
+
17
+ # KYA tools
18
+ from langchain_nuggets.tools.kya import (
19
+ GetAgentTrustScore,
20
+ RegisterAgentIdentity,
21
+ VerifyAgentIdentity,
22
+ )
23
+
24
+ # KYC tools
25
+ from langchain_nuggets.tools.kyc import (
26
+ CheckKycStatus,
27
+ InitiateKycVerification,
28
+ VerifyAge,
29
+ VerifyCredential,
30
+ )
31
+
32
+ # LangGraph auth (optional — requires langgraph-sdk)
33
+ try:
34
+ from langchain_nuggets.langgraph import NuggetsAuth, NuggetsAuthError
35
+ except ImportError:
36
+ pass
37
+
38
+ # Authority Middleware (optional — requires langchain-core)
39
+ try:
40
+ from langchain_nuggets.middleware import (
41
+ MiddlewareConfig,
42
+ NuggetsAuthorityMiddleware,
43
+ ProofArtifact,
44
+ )
45
+ except ImportError:
46
+ pass
47
+
48
+ __all__ = [
49
+ # Toolkit
50
+ "NuggetsToolkit",
51
+ # Client
52
+ "NuggetsApiClient",
53
+ "NuggetsApiClientError",
54
+ # Base
55
+ "NuggetsBaseTool",
56
+ # KYC
57
+ "InitiateKycVerification",
58
+ "CheckKycStatus",
59
+ "VerifyAge",
60
+ "VerifyCredential",
61
+ # KYA
62
+ "RegisterAgentIdentity",
63
+ "VerifyAgentIdentity",
64
+ "GetAgentTrustScore",
65
+ # Auth
66
+ "RequestCredentialPresentation",
67
+ "VerifyPresentation",
68
+ "InitiateOAuthFlow",
69
+ "CheckAuthStatus",
70
+ # LangGraph (optional)
71
+ "NuggetsAuth",
72
+ "NuggetsAuthError",
73
+ # Middleware (optional)
74
+ "NuggetsAuthorityMiddleware",
75
+ "MiddlewareConfig",
76
+ "ProofArtifact",
77
+ ]
@@ -0,0 +1,3 @@
1
+ from langchain_nuggets.client.nuggets_api_client import NuggetsApiClient, NuggetsApiClientError
2
+
3
+ __all__ = ["NuggetsApiClient", "NuggetsApiClientError"]
@@ -0,0 +1,192 @@
1
+ """Nuggets API client with automatic authentication and token caching."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import time
6
+ from typing import Any, Dict, Optional, Union
7
+
8
+ import httpx
9
+
10
+
11
+ class NuggetsApiClientError(Exception):
12
+ """Error from the Nuggets API."""
13
+
14
+ def __init__(self, message: str, code: str, status_code: int) -> None:
15
+ super().__init__(message)
16
+ self.code = code
17
+ self.status_code = status_code
18
+
19
+
20
+ class NuggetsApiClient:
21
+ """HTTP client for the Nuggets API with automatic auth token management."""
22
+
23
+ def __init__(self, config: Dict[str, Any]) -> None:
24
+ self._api_url: str = config["api_url"]
25
+ self._partner_id: str = config["partner_id"]
26
+ self._partner_secret: str = config["partner_secret"]
27
+ self._token: Optional[Dict[str, Any]] = None
28
+ self._sync_client: Optional[httpx.Client] = None
29
+ self._async_client: Optional[httpx.AsyncClient] = None
30
+
31
+ # TLS configuration for self-hosted deployments
32
+ verify_ssl: bool = config.get("verify_ssl", True)
33
+ ca_cert: Optional[str] = config.get("ca_cert")
34
+ if not verify_ssl:
35
+ self._verify: Union[bool, str] = False
36
+ elif ca_cert is not None:
37
+ self._verify = ca_cert
38
+ else:
39
+ self._verify = True
40
+
41
+ def _get_sync_client(self) -> httpx.Client:
42
+ if self._sync_client is None:
43
+ self._sync_client = httpx.Client(verify=self._verify)
44
+ return self._sync_client
45
+
46
+ def close(self) -> None:
47
+ """Close the sync HTTP client and release resources."""
48
+ if self._sync_client is not None:
49
+ self._sync_client.close()
50
+ self._sync_client = None
51
+
52
+ async def aclose(self) -> None:
53
+ """Close the async HTTP client and release resources."""
54
+ if self._async_client is not None:
55
+ await self._async_client.aclose()
56
+ self._async_client = None
57
+
58
+ def __enter__(self) -> "NuggetsApiClient":
59
+ return self
60
+
61
+ def __exit__(self, *args: Any) -> None:
62
+ self.close()
63
+
64
+ async def __aenter__(self) -> "NuggetsApiClient":
65
+ return self
66
+
67
+ async def __aexit__(self, *args: Any) -> None:
68
+ await self.aclose()
69
+
70
+ def _authenticate_sync(self) -> str:
71
+ if self._token and self._token["expires_at"] > time.time():
72
+ return self._token["access_token"]
73
+ client = self._get_sync_client()
74
+ response = client.post(
75
+ f"{self._api_url}/partner/auth",
76
+ json={"partnerId": self._partner_id, "partnerSecret": self._partner_secret},
77
+ )
78
+ if response.status_code >= 400:
79
+ raise NuggetsApiClientError(
80
+ "Authentication failed", "AUTH_FAILED", response.status_code
81
+ )
82
+ data = response.json()
83
+ self._token = {
84
+ "access_token": data["token"],
85
+ "expires_at": time.time() + data["expiresIn"],
86
+ }
87
+ return self._token["access_token"]
88
+
89
+ def _request_sync(self, method: str, path: str, body: Any = None) -> Any:
90
+ token = self._authenticate_sync()
91
+ client = self._get_sync_client()
92
+ kwargs: Dict[str, Any] = {
93
+ "method": method,
94
+ "url": f"{self._api_url}{path}",
95
+ "headers": {
96
+ "Content-Type": "application/json",
97
+ "Authorization": f"Bearer {token}",
98
+ },
99
+ }
100
+ if body is not None:
101
+ kwargs["content"] = json.dumps(body)
102
+ response = client.request(**kwargs)
103
+ try:
104
+ data = response.json()
105
+ except Exception:
106
+ if response.status_code >= 400:
107
+ raise NuggetsApiClientError(
108
+ f"Request failed with status {response.status_code}",
109
+ "UNKNOWN",
110
+ response.status_code,
111
+ )
112
+ raise NuggetsApiClientError(
113
+ "Invalid JSON response", "PARSE_ERROR", response.status_code
114
+ )
115
+ if response.status_code >= 400:
116
+ raise NuggetsApiClientError(
117
+ data.get("message", "Request failed"),
118
+ data.get("code", "UNKNOWN"),
119
+ response.status_code,
120
+ )
121
+ return data
122
+
123
+ def get(self, path: str) -> Any:
124
+ return self._request_sync("GET", path)
125
+
126
+ def post(self, path: str, body: Any = None) -> Any:
127
+ return self._request_sync("POST", path, body)
128
+
129
+ # --- Async methods ---
130
+ async def _get_async_client(self) -> httpx.AsyncClient:
131
+ if self._async_client is None:
132
+ self._async_client = httpx.AsyncClient(verify=self._verify)
133
+ return self._async_client
134
+
135
+ async def _authenticate_async(self) -> str:
136
+ if self._token and self._token["expires_at"] > time.time():
137
+ return self._token["access_token"]
138
+ client = await self._get_async_client()
139
+ response = await client.post(
140
+ f"{self._api_url}/partner/auth",
141
+ json={"partnerId": self._partner_id, "partnerSecret": self._partner_secret},
142
+ )
143
+ if response.status_code >= 400:
144
+ raise NuggetsApiClientError(
145
+ "Authentication failed", "AUTH_FAILED", response.status_code
146
+ )
147
+ data = response.json()
148
+ self._token = {
149
+ "access_token": data["token"],
150
+ "expires_at": time.time() + data["expiresIn"],
151
+ }
152
+ return self._token["access_token"]
153
+
154
+ async def _request_async(self, method: str, path: str, body: Any = None) -> Any:
155
+ token = await self._authenticate_async()
156
+ client = await self._get_async_client()
157
+ kwargs: Dict[str, Any] = {
158
+ "method": method,
159
+ "url": f"{self._api_url}{path}",
160
+ "headers": {
161
+ "Content-Type": "application/json",
162
+ "Authorization": f"Bearer {token}",
163
+ },
164
+ }
165
+ if body is not None:
166
+ kwargs["content"] = json.dumps(body)
167
+ response = await client.request(**kwargs)
168
+ try:
169
+ data = response.json()
170
+ except Exception:
171
+ if response.status_code >= 400:
172
+ raise NuggetsApiClientError(
173
+ f"Request failed with status {response.status_code}",
174
+ "UNKNOWN",
175
+ response.status_code,
176
+ )
177
+ raise NuggetsApiClientError(
178
+ "Invalid JSON response", "PARSE_ERROR", response.status_code
179
+ )
180
+ if response.status_code >= 400:
181
+ raise NuggetsApiClientError(
182
+ data.get("message", "Request failed"),
183
+ data.get("code", "UNKNOWN"),
184
+ response.status_code,
185
+ )
186
+ return data
187
+
188
+ async def aget(self, path: str) -> Any:
189
+ return await self._request_async("GET", path)
190
+
191
+ async def apost(self, path: str, body: Any = None) -> Any:
192
+ return await self._request_async("POST", path, body)
@@ -0,0 +1,25 @@
1
+ """LangGraph auth integration with Nuggets identity provider.
2
+
3
+ Requires the ``langgraph`` extra::
4
+
5
+ pip install langchain-nuggets[langgraph]
6
+ """
7
+ from langchain_nuggets.langgraph.auth import NuggetsAuth
8
+ from langchain_nuggets.langgraph.authorization import (
9
+ ownership_filter,
10
+ require_kyc,
11
+ require_scopes,
12
+ )
13
+ from langchain_nuggets.langgraph.token_verifier import NuggetsAuthError, NuggetsTokenVerifier
14
+ from langchain_nuggets.langgraph.types import NuggetsAuthConfig, NuggetsUserInfo
15
+
16
+ __all__ = [
17
+ "NuggetsAuth",
18
+ "NuggetsAuthConfig",
19
+ "NuggetsAuthError",
20
+ "NuggetsTokenVerifier",
21
+ "NuggetsUserInfo",
22
+ "ownership_filter",
23
+ "require_kyc",
24
+ "require_scopes",
25
+ ]