Repository navigation
fix(plugins): keep open edx credentials on the server - #969
Merged
abdulrafey1 merged 23 commits intoOct 26, 2026
Merged
Conversation
Add a ConfigAdapter base with no-op preprocess, postprocess and sync_cache steps. CONFIG_ADAPTERS now holds ConfigAdapter, and LLMConfigAdapter subclasses it, so a plugin overrides only the steps it needs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Open edX client grants its own access token from the user's stored settings and caches it per user in Redis, retrying once on a 401. Every Open edX tool loads the calling user's stored settings instead of taking URLs, credentials or tokens from the model, and the authenticate and refresh-token tools are gone. Open edX settings never enter the prompt. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Saving Open edX settings through the config route now deletes that user's cached access token, so the next call grants one with the new credentials. The sync_cache docs example now shows where a plugin gets its cache. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…er-base Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Say that sync_cache runs only after the PUT config route, not the first POST configure, and that a CONFIG_ADAPTERS entry is any ConfigAdapter overriding only the steps it needs. Wrap the plugin guide lines this branch edited to 120 characters and give sync_cache a docstring body in place of its redundant return. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The plugin-facing CacheService methods and get_cache_service now say what they return, how a None or 0 ttl falls back to the default, and that a Redis error is logged and swallowed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The config route test now also checks that the response returns the saved Open edX config unchanged while the cached token is dropped. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
zaira-bibi
requested changes
Oct 26, 2026
…er-base Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…er-base Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…est helpers openedx_get_user_info is now openedx_check_settings in the openedx-settings category, following the <lms>_check_settings convention the chat rules name; it still returns the signed-in account. The stored-settings fixture is opt-in, so the real-storage test needs no patch-back, and the credential and real-storage tests use the sparkth.lib.testing helpers. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ocstring Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
OpenEdxClient.studio_url normalises the stored Studio URL once, and the tools and helpers use it and the LMS base_url, so no call site rebuilds or forgets the trailing-slash strip. The helpers that took config or studio_url only to rebuild that URL no longer take them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
OpenEdxClient now takes the Sparkth user it acts for, so its signature says it needs one and it no longer reads current_user_id itself. _open_client is the one place the tools read the caller and their stored settings; the create and update helpers take its open client, so a tool that makes several calls reuses one client. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The cached token's key now carries an HMAC of the LMS URL, username and password, keyed with the server secret. Saving new settings moves the user to a new key, so OpenEdxConfigAdapter and the general config adapter hook it needed are gone; the old token just expires. This also closes the window in which a request could reuse the old token right after a settings change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…pers create_basic_component and update_xblock_content are helpers the tools call, not tools, so they no longer carry the openedx_ prefix, like set_course_language. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
FakeRedis and a fake_redis fixture that installs it on the shared CacheService move to sparkth.lib.testing. The fixture is opt-in, so only the Open edX tests that grant a token ask for it, and the resend rate-limit test reuses the class in place of its own copy. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
abdulrafey1
changed the base branch from
rafe/config-adapter-base
to
rafe/lms-settings-canvas-moodle
October 26, 2026 13:01
…-openedx Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
zaira-bibi
approved these changes
Oct 26, 2026
zaira-bibi
left a comment
Contributor
There was a problem hiding this comment.
looks good! please try to not have more than 10 files in the PRs.
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.
What
Open edX tools no longer take a password, an access token or LMS URLs from the model. The Open edX
client gets and caches its own access token with the user's stored settings, so the password never
reaches the chat prompt and the token never passes through the model.
Changes
OpenEdxClient(config, user_id)runs the OAuth2 password grant with the storedusername and password on first use, then caches the token in Redis under
openedx:access-token:<user_id>:<digest>. The digest is an HMAC-SHA256, keyed withSECRET_KEY, ofthe stored LMS URL, username and password. Saving new settings moves the user to a new key, and the
old token expires on its own. The key shows none of the settings. The TTL is
expires_inminus 60 s,or the cache default when Open edX sends no expiry.
second 401 is reported. A token-response error never includes the response body, in the message or
in a chained cause.
OpenEdxClient.studio_urlgives the Studio base URL from the stored settings. Thetools open a client through one
_open_client()factory, which loads the caller's settings and userid. The tool helpers (
create_basic_component,update_xblock_content, …) take the open client.openedx_authenticateandopenedx_refresh_access_tokentools are removed, and sois every
authfield.openedx_get_user_infobecomesopenedx_check_settings(categoryopenedx-settings): it takes no arguments, checks the stored settings and returns the signed-in account.openedx_add_plugin_contentloads settings before resolving the contributor, so an unconfigured usernever creates contributor content.
OpenEdxConfigdropsto_lms_credentials_hint.sparkth.lib.cacheexposesCacheServiceandget_cache_serviceto plugins. Theirdocstrings now describe the API, and the API reference lists the module.
sparkth.lib.testinggainsFakeRedisand an opt-infake_redisfixture that routes theshared
CacheServiceto it. The email-verification test uses the sameFakeRedis.How to Test
uv run pytest sparkth/plugins/openedx tests/api/v1/test_auth_email_verification.py -v.test_client.pychecks that:expires_in;authenticate step happens, and every call succeeds.
Notes
Breaking for MCP clients: the two auth tools are gone and the Open edX tool schemas no longer accept
auth. On/ai/mcpno user is bound, so these tools fail withNoAuthenticatedUser.The token is cached in Redis (
REDIS_URL, already required) as plain text. It is a short-lived accesstoken whose cache entry expires with it, and the password is never cached. No new env var, no migration.
This description was written with the assistance of an LLM (Claude).
🤖 Generated with Claude Code