--- id: "59eafa1c-0173-46b3-a74c-0dd516cd0ea6" name: "Canvas File Download" micro_summary: "Describes retrieving authenticated Canvas files by finding a module file ID, using its session cookie with curl, and extracting PDF text; stresses deleting sensitive temporary artifacts." status: "in_progress" see_also: [] scope: "Retrieving authenticated Canvas course files (syllabus PDFs, lab sheets) when in-page fetch is blocked. Covers locating a module file id, exporting the canvas_session cookie via CDP, curling the download URL, and reading the PDF text." --- ## Verified 2026-09-23 on sfsu.instructure.com (DS 601 syllabus PDF) ### Why not in-page fetch `js()` + `fetch('/files//download?download_frd=1')` fails with `TypeError: Failed to fetch`, thrown from Canvas's own patched `fetch` in `main-entry-*.js`. Course JSON APIs (`/api/v1/...`) work fine in-page; binary file downloads do not. Do not escalate this to a navigation — downloading via the browser tab means fighting the PDF viewer. ### Path that works 1. **Find the file id.** Syllabus is usually a File module item, not a page (`/api/v1/courses//pages` returns "That page has been disabled for this course"): ```js // modules -> module items -> content_id is the file id fetch('/api/v1/courses/75477/modules').then(r=>r.json()) fetch('/api/v1/courses/75477/modules//items').then(r=>r.json()) // {title:"Syllabus", type:"File", content_id:9670019} fetch('/api/v1/courses/75477/files/9670019') // -> display_name, url, content-type ``` 2. **Export the session cookie through CDP, then curl.** Only 3 cookies exist for the host (`canvas_session`, `log_session_id`, `_csrf_token`); `canvas_session` is what authenticates. ```python r = cdp("Network.getCookies", urls=["https://sfsu.instructure.com"]) open('/tmp/ck.txt','w').write("; ".join(f"{c['name']}={c['value']}" for c in r['cookies'])) ``` ```bash curl -sL -H "Cookie: $(cat /tmp/ck.txt)" -o syllabus.pdf \ "https://sfsu.instructure.com/files/9670019/download?download_frd=1" file syllabus.pdf # must say PDF document, not HTML ``` 3. **Extract text** — no `pdftotext`/`mutool`/`gs` on this machine, `textutil` does not read PDF: ```bash uvx --from pdfminer.six pdf2txt.py -o syllabus.txt syllabus.pdf ``` 4. **Delete the cookie file and the PDF/text when done.** The cookie is a live authenticated `canvas_session`; leaving it on disk is a session hijack in file form. ### Notes - Read-only API GETs from the user's existing Dashboard tab need no navigation, so the tab is left exactly as found (see Existing Tab Workflow). - `pdfminer.six` here was a throwaway `uvx` dependency, not installed durably. If PDF reads become routine, add a real PDF extractor to the dev shell instead of re-resolving it each time. - Course-side use of this: College tree `DS 601` / `Published-course Attendance Map` grading policy came from this path.