- name
- canvas-lms-idp-auto-refresh
- description
- Auto-refresh Canvas LMS API tokens via institutional IDP (CAS/SAML) login. Use when: (1) Canvas API returns 401 and you need to re-authenticate, (2) setting up automated token lifecycle for any Canvas LMS deployment behind an institutional SSO (especially Chinese universities using id.fudan.edu.cn style IDP), (3) user asks about "canvas token expired", "自动刷新token", "elearning login", "IDP登录". Handles RSA-encrypted password auth, SSO ticket exchange, token creation and old token cleanup.
Canvas LMS — IDP Auto Token Refresh
Automate Canvas API token refresh by replaying institutional IDP login (CAS/SAML) with RSA-encrypted credentials.
How It Works
Entry URL → CAS/IDP (lck + authChainCode) → RSA encrypt password → authExecute
→ loginToken (JWT) → authnEngine → SSO ticket → Canvas session → create API token
→ (optional) delete old tokens by purpose → output NEW_TOKEN=xxxThe script handles the full IDP chain: cookie juggling, JavaScript-redirect handoff, CSRF extraction, and Canvas API token CRUD.
Quick Start
1. Install Dependencies
cd scripts/
python3 -m venv .venv
.venv/bin/pip install -r requirements.txtDependencies: requests, beautifulsoup4, pycryptodome, python-dotenv.
2. Configure Credentials
Copy .env.example to .env and fill in:
cp scripts/.env.example scripts/.envRequired fields:
ELEARNING_USERNAME— student/staff IDELEARNING_PASSWORD— password
Optional (defaults to Fudan eLearning):
ELEARNING_ENTRY_URL— CAS entry pointELEARNING_IDP_BASE_URL— IDP base URLELEARNING_ENTITY_ID— SP entity IDELEARNING_TOKEN_PURPOSE— label for created tokens (default: "OpenClaw Auto Refresh Token")ELEARNING_CLEANUP_OLD_TOKENS— auto-delete old tokens with same purpose (default: false)
3. Run
# Full flow: login → create token → cleanup old tokens
cd scripts && .venv/bin/python elearning_login.py --cleanup-old-tokens
# Debug mode (verbose HTTP logs + save debug artifacts)
cd scripts && .venv/bin/python elearning_login.py --debug --cleanup-old-tokens
# Dry-run: only test up to public key fetch (no login)
cd scripts && .venv/bin/python elearning_login.py --dry-run --debugOn success, the script prints NEW_TOKEN=<token_value> to stdout.
4. Integrate with Token Lazy-Loading
For agents that call Canvas API, implement a lazy-refresh pattern:
- Read saved token from file
- Validate with
GET /api/v1/users/self— check HTTP status only (don't read body) - If 200 → use token
- If 401 → run refresh script, capture
NEW_TOKEN=, save to file, retry - If refresh also fails → alert user (password changed, CAPTCHA triggered, etc.)
Key rules:
- Validate once per session, not on every API call
- Only re-validate on explicit 401 responses
- Don't log or expose raw token values
- The refresh takes ~2-3 seconds, run silently
Security
.envcontains credentials — never commit to git (.envis gitignored by default)debug_output/may contain session cookies and encrypted payloads — sanitize before sharing- The script uses PKCS1v1_5 RSA encryption for password transport (matching the IDP's JS frontend)
- Tokens are created with a purpose label for lifecycle management
- Old tokens with matching purpose can be auto-deleted to avoid accumulation
Known Limitations
| Limitation | Impact | Mitigation |
|---|---|---|
| CAPTCHA/rate-limiting | Script cannot solve human verification | Alert user, manual intervention needed |
| MFA/2FA | Requires interactive flow not supported by requests | Not supported; alert user |
| IDP interface changes | JSON field names or HTML structure may change | Debug output (--debug) captures raw responses for diagnosis |
| Public key format changes | Script supports PEM, Base64-DER, modulus+exponent | If new format appears, extend parse_public_key_payload() |
Troubleshooting
Run with --debug to save artifacts to debug_output/:
| Symptom | Check |
|---|---|
未能从入口响应中解析到 lck | debug_output/entry_response.html — look for context_CAS_... |
queryAuthMethods 未找到 userAndPwd | debug_output/query_auth_methods.json — check moduleCode field |
未从 authExecute 提取到 loginToken | debug_output/auth_execute.json — check code/message |
未拿到关键会话 Cookie | Check auth_execute.json for errors, authn_engine_response.html for CAPTCHA |
| Token API returns 401/422 | debug_output/cookies.txt for _csrf_token / _normandy_session |
| Cleanup fails | debug_output/cleanup_summary.json for failed entries |
Adapting to Other Institutions
The IDP flow is based on a common CAS/SAML pattern used by many Chinese universities. To adapt:
- Change URLs in
.env:ELEARNING_ENTRY_URL,ELEARNING_IDP_BASE_URL,ELEARNING_ENTITY_ID - Test with
--dry-runfirst to verifylck/authChainCodeextraction - If IDP uses different auth methods: modify
pick_auth_chain_code()inauth_session.py - If password encryption differs: modify
encrypt_password_rsa()andparse_public_key_payload()
Tested with: Fudan University (id.fudan.edu.cn → elearning.fudan.edu.cn).