Tutor Site Content in IFRAME

We are currently running Koa via tutor, and running into X_FRAME_OPTIONS or Content security policy where the LMS/CMS can’t be included in an iframe outside of the origin domain. Has anyone come across this and have a solution?

Here is an example of Firefox

and Chrome:


This problem is not related to Tutor (or Open edX), but to the web server hosting the embedded content. You have to configure the Content Security Policy on your webserver to allow your Open edX site to access the embedded content. Viewing the error in the Chrome console should tell exactly what is blocked and the configuration required.

Here is a configuration that we use on our sites hosting the embedded content to limit who or which sites can embed our content. Perhaps you will find it useful:

# Template code:
Content-Security-Policy: frame-ancestors 'self' yoursites;

# Our settings to allow access to the root and all subdomains (such as edx.site1.com,  preview.edx.site1.com and studio.edx.site1.com)
Content-Security-Policy: frame-ancestors 'self' site1.com *.site1.com site2.com *.site2.com;

These resources might help you:

1 Like

Thanks, it did talk about CSP and X_FRAME_OPTIONS., and I tried adding frame-src https://{{ LMS_HOST}} but didn’t work and still was talking about X_FRAME_OPTIONS blocking it, which LMS/CMS is hard-coded I believe to be “SAMEORIGIN”

Is there way to wildcard all hosts, or is this something we will have to keep maintaining for every possible user who uses our courses?

I will try frame-ancestors

I interpreted your problem that you were embedding content in an Open edX course. Reading it closer, you want to embed Open edX in another site. My bad. :slight_smile:

The wildcard * should work for frame-ancestors (see CSP: frame-ancestors - HTTP | MDN and http - How to allow all frame ancestors with CSP header? - Stack Overflow). I used it before, but it took some trial and error.

I’ve tried modifying the Nginx CSP in Tutor but without success. Perhaps you will have better luck :grin:

Thanks @tony-h! I am getting closer. I have chrome working, but Firefox redirects the page on load to what is the iframe src url, instead of just loading it in the iframe, so working on trying to get that working.

I will post my “plugin” config once I get it working.

We just ran into a CORS issue because of the deprecated allow-from flag. It shows up when embedding a PDF file using the pdfXBlock and then trying to initiate a fetch request in a raw HTML block (using a link to a JS file). The fetch requests work without a problem on other pages. The PDF document displays correctly regardless.

Just by curiosity @misilot why would you want to embed your Open edX website inside an iframe?

@tony-h I think you could do something like

name: tutor-cors
version: 1.0.0
  nginx-lms: |
    add_header Access-Control-Allow-Origin *;

@regis we have instructors who embed certain lessons into their courses either via LTI or via an iframe. An example of this can be seen here here. It is redirecting (Chrome stops it, Firefox continues) currently due to the flag allow_iframing being False. So far I haven’t found a way to overwrite this value yet.
Template code that causes the redirect

I think the idea is, it is similar to using within a LTI environment, but where we aren’t tying back to a specific user or course but embedding in a regular webpage (like above) where those interested can work through the material.


1 Like

@misilot, thanks for the plugin.

I had to add proxy_hide_header to the plugin to clear the Invalid 'X-Frame-Option' message (but I’m not sure if that HTTP error actually caused any problems because the PDF document still displays). Even so, there must be some correlation because the fetch command in a Raw HTML block tended to only fail on pages with an embedded PDF document with the Invalid 'X-Frame-Option' header. It didn’t fail every time, which makes it hard to pinpoint the root cause.

Here is the original error using the pdfXBlock:

Here is the modified plugin if others need to embed Open edX as an iframe or clear headers:

name: tutor-cors
version: 1.0.0
  nginx-lms: |
    add_header Access-Control-Allow-Origin *;
    proxy_hide_header X-Frame-Options;

Dev notes:

Nginx has three ways to remove HTTP response headers.

  1. proxy_set_header had no impact

    proxy_set_header X-Frame-Options "";
  2. more_clear_headers fails because Nginx plugin ngx_headers_more is not installed

    more_clear_headers X-Frame-Options;

    Nginx error:

    nginx: [emerg] unknown directive "more_clear_headers" in /etc/nginx/conf.d/lms.conf:46
  3. proxy_hide_header successfully removed the HTTP header so that the client does not see it.

    proxy_hide_header X-Frame-Options;
1 Like

To follow up on this, here is our plugin to fix the X-Frame-Option error.

name: custom-http-headers
version: 1.0.0
  nginx-lms: |
    # Fix obsolete header in the pdfXBlock
    proxy_hide_header X-Frame-Options;
    add_header X-Frame-Options SAMEORIGIN;

I had similar error when trying to use learning MFE.
It seems like in the learning MFE, the course information is displayed in iframe whose source is the lms base. But my learning MFE was hosted in apps.lms like other MFEs are by default in tutor. So the course information doesn’t load and the spinner keeps going forever.
Adding this plugin didn’t help.
Maybe I should allow the apps.lms domain to make request to the base lms?
But that should be enabled by default, I would surmise.
Any help here?

Just to clarify further, without using the aforementioned plugin, I am getting this error:

Preformatted textRefused to display 'https://courses.edx.org/' in a frame because it set 'X-Frame-Options' to 'deny'.

I have no idea why am I seeing courses.edx.org there and not my lms base url, which I have set and is also set in the tutor-mfe plugin
And when I use the plugin, this is the error I get

Refused to display 'https://lms.bloomed.org.np/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

@sumanchapai it looks like you are describing a few bugs about both Open edX and Tutor here.

Could you please provide screenshots and urls for those two issues, such that we are able to easily replicate them? We can then track them in this Github issue.