feat: add token vault support for auth0-ai-ms-agent SDK#60
Open
adam-wang-okta-public wants to merge 1 commit intomainfrom
Open
feat: add token vault support for auth0-ai-ms-agent SDK#60adam-wang-okta-public wants to merge 1 commit intomainfrom
adam-wang-okta-public wants to merge 1 commit intomainfrom
Conversation
Quickly reviewed it with ClaudePR ReviewThe core logic is sound — framework kwargs stripping, context building, 🔴 Critical (blocking)
[tool.poetry.dependencies]
auth0-ai = { path = "../auth0-ai", develop = true } # won't resolve from PyPI
Anyone who runs pip install auth0-ai-ms-agent will get a broken package. The LangChain adapter handles this correctly — version pin in
main deps, path override in dev deps:
[tool.poetry.dependencies]
auth0-ai = "^1.0.x"
[tool.poetry.group.dev.dependencies]
auth0-ai = { path = "../auth0-ai", develop = true }
---
🟠 Major
Dead openfga-sdk dependency
openfga-sdk = "^0.9.5" is listed but there is no FGA code in this package. The other adapters include it because they ship FGA support —
this one is token-vault only. Remove it to avoid unnecessary transitive dependencies for all users.
---
TokenVaultAuthorizer incorrectly inherits from ABC
token_vault_authorizer.py:11 — TokenVaultAuthorizer is a concrete class, it's directly instantiated in auth0_ai.py. Declaring it abstract
is contradictory. TokenVaultAuthorizerBase is Generic, not ABC, so this isn't even inherited. The boilerplate __init__ that only calls
super() can also be removed entirely.
# current
class TokenVaultAuthorizer(TokenVaultAuthorizerBase, ABC):
def __init__(self, params, auth0=None):
super().__init__(params, auth0)
# suggested
class TokenVaultAuthorizer(TokenVaultAuthorizerBase):
pass # or just remove __init__ entirely
---
inspect._empty is a private API
tool_wrapper.py:45:
# current — uses private implementation detail
if value is not None or param.default is inspect._empty:
# fix — use the public API
if value is not None or param.default is inspect.Parameter.empty:
---
Non-serializable exception stored in session state
tool_wrapper.py:92:
session.state["pending_interrupt"] = e # stores a live Python exception object
If AgentSession.state is ever persisted between turns (Redis, DB, over the wire) — which is the point of a session in multi-turn
conversations — serializing a Python exception will fail. The data callers actually need (connection, scopes, required_scopes,
authorization_params) is all on the interrupt object; the exception wrapper is not necessary. The README's isinstance(interrupt,
TokenVaultInterrupt) check also couples callers to never persisting state. At minimum this constraint should be clearly documented;
ideally the stored value is a plain serializable dict.
---
pending_interrupt is never cleared on subsequent runs
After a TokenVaultInterrupt, session.state["pending_interrupt"] is written but never cleaned up. If the user completes authorization and
the agent runs successfully on the next turn, the stale interrupt is still present. Any caller checking
session.state.get("pending_interrupt") after a successful run will see a false positive.
Simple fix — clear it at the start of each invocation before calling protect_fn:
session.state.pop("pending_interrupt", None)
---
🟡 Minor
**params: TokenVaultAuthorizerParams type annotation is misleading
auth0_ai.py:27 — **params: T means "each kwarg value has type T", not "these kwargs together conform to T's shape".
TokenVaultAuthorizerParams is a regular class, not a TypedDict. The annotation doesn't give callers useful IDE autocomplete and is
semantically incorrect. Either annotate as **kwargs: Any or explicitly declare each parameter mirroring the
TokenVaultAuthorizerParams.__init__ signature.
---
_schema_supplied private attribute is fragile
tool_wrapper.py:96:
schema_or_model = tool.parameters() if getattr(tool, "_schema_supplied", False) else input_model
_schema_supplied is a private attribute on an RC-stage FunctionTool. The getattr default of False means if this attribute is renamed or
removed in a future framework version, this silently falls back to input_model with no error — just a quiet schema regression. Deserves a
comment explaining why it's needed and what the silent fallback means, so it's easy to audit on framework upgrades.
---
_FRAMEWORK_KWARGS risk going stale silently
The set is a deny-list of framework-injected kwargs derived from a specific line in the RC framework. When the framework graduates from RC
and adds/removes injected kwargs, this set won't update automatically. If a new framework kwarg isn't listed here it leaks into
original_func as an unexpected argument. The comment linking to the source line is good — worth also noting explicitly that this is a
maintenance point that needs revisiting on each framework version bump.
---
Missing pytest asyncio mode configuration
With pytest-asyncio = "^0.25.0", omitting asyncio_mode in pyproject.toml produces deprecation warnings. Add:
[tool.pytest.ini_options]
asyncio_mode = "auto"
---
Missing newline at end of token_vault_authorizer.py
---
🔵 Test coverage gaps
- No test for stale pending_interrupt being cleared on a successful retry — would directly catch the issue raised above.
- tool_call_id uniqueness is untested — the PR explicitly notes this is generated per-invocation as a design decision; worth asserting
that two successive invocations produce distinct tool_call_id values in their contexts.
- No test for the non-_schema_supplied path — test_returned_function_tool_preserves_schema_supplied_input_model covers the schema dict
path but not the pydantic model path. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds the auth0-ai-ms-agent package — an Auth0 AI SDK adapter for the https://github.com/microsoft/agent-framework.
This PR implements the Token Vault feature, which allows MS Agent tools to obtain access tokens for third-party APIs (Google, GitHub, Slack, etc.) on behalf of the user via Auth0's Token Vault.
Public API example
Implementation details
Note
original_funcis called directly rather than through FunctionTool.call to avoid double-counting invocation metrics already tracked at the wrapped tool boundary.tool_call_idis generated per invocation (rather than forwarded from the framework) because FunctionTool.invoke() consumes it before it reaches the wrapped function.agent-frameworkto^1.0.0rc2Testing
Manual QA
Unit test
Unit tests are provided in tests/test_auth0_ai.py (15 tests, 100% coverage).
protect()logic runs for real, catching any interface mismatches between the adapter and the core SDK.Test coverage includes:
Decorator contract (returns callable, preserves tool name, description, schema, and all framework configuration)
Authorization pass path for both sync and async tool functions
Authorization fail path (TokenVaultInterrupt raised, session state set, original function not executed)
Framework kwargs stripping before calling the original function
Non-TokenVaultInterrupt exceptions propagate unchanged without setting session state
RuntimeError raised when no session is provided
To run tests:
cd packages/auth0-ai-ms-agent poetry install poetry run pytest tests/ --cov=auth0_ai_ms_agent --cov-report=term-missing -vChecklist
References