openedx / openedx/openedx-platform

[LTI Provider] iframe-embedded problem submissions fail with CSRF 403 under Django cookie defaults

Open
#38,441 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
8.2k
Forks
4.4k
Avg merge
6d 18h
Merged PRs (30d)
42

Description

Summary

When Open edX is used as an LTI 1.1 tool provider and content is launched inside an iframe on the consumer LMS (verified with Canvas), the initial launch renders correctly, but any subsequent interactive POST (e.g. submitting a problem) is rejected by Django's CSRF middleware with:

Forbidden (CSRF cookie not set.): /courses/.../xblock/.../handler/xmodule_handler/problem_check

The same content works if launched in a new tab / top-level window.

Steps to reproduce
  1. Configure an Open edX instance as an LTI 1.1 provider (default settings, no changes to SESSION_COOKIE_SAMESITE / CSRF_COOKIE_SAMESITE).
  2. In Canvas, add an external tool pointing to a problem component or subsection in the Open edX course.
  3. Launch the tool inside Canvas (iframe, default behavior).
  4. Attempt to submit an answer.
Expected

The problem submission succeeds and (if the component is graded) the score is passed back to Canvas.

Actual

POST to the xblock handler returns HTTP 403. LMS logs:

WARNING django.security.csrf ... Forbidden (CSRF cookie not set.): /event
WARNING django.security.csrf ... Forbidden (CSRF cookie not set.): /courses/<course>/xblock/<block>/handler/xmodule_handler/problem_check
[pid: 30] POST /event => 403
[pid: 31] POST /courses/<course>/xblock/<block>/handler/xmodule_handler/problem_check => 403
Root cause
  • lti_launch (lms/djangoapps/lti_provider/views.py) is @csrf_exempt, so the initial launch POST from Canvas works.
  • Subsequent XBlock handler POSTs are standard CSRF-protected views.
  • Django defaults are SESSION_COOKIE_SAMESITE = 'Lax' and CSRF_COOKIE_SAMESITE = 'Lax' (lms/envs/common.py does not override them; it only defines DCS_SESSION_COOKIE_SAMESITE).
  • Browsers do not send Lax cookies on cross-site POSTs from the Canvas iframe, so the CSRF cookie is absent and Django rejects the request.
Environment
  • Open edX master sandbox
  • LTI version: 1.1
  • Consumer LMS: Canvas
  • Browser: Firefox 149 (macOS 10.15)
Related code
  • lms/djangoapps/lti_provider/views.py (lti_launch view, @csrf_exempt + @add_p3p_header)
  • lms/envs/common.py (DCS_SESSION_COOKIE_SAMESITE exists, but SESSION_COOKIE_SAMESITE / CSRF_COOKIE_SAMESITE do not)
  • lms/djangoapps/lti_provider/users.py (require_user_account enforcement)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with lms/djangoapps/lti_provider/views.py and lms/envs/common.py, then trace the lti_launch flow and Django cookie settings involved in the iframe request. Reproduce the Canvas iframe launch and problem submission, checking the CSRF cookie and handler response. Done means the interactive POST succeeds in the iframe while top-level launches continue to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.