Task #87528

VimeoHelper/AbstractOEmbedHelper must send Referer Header to fetch proper oEmbed.json for videos with restricted embedding.

Added by Leonie Philine Bitto 7 months ago. Updated 6 months ago.

Should have
File Abstraction Layer (FAL)
Target version:
Start date:
Due date:
% Done:


TYPO3 Version:
PHP Version:
Sprint Focus:


VideoHelper uses an oEmbed request, as documented here: https://developer.vimeo.com/api/oembed/videos

curl 'https://vimeo.com/api/oembed.json?width=2048&url=https%3A%2F%2Fvimeo.com%2F123456789' | python -m json.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   387  100   387    0     0   1646      0 --:--:-- --:--:-- --:--:--  1646
    "domain_status_code": 403,
    "height": 1152,
    "html": "<iframe src=\"https://player.vimeo.com/video/123456789?app_id=122963\" width=\"2048\" height=\"1152\" frameborder=\"0\" allow=\"autoplay; fullscreen\" allowfullscreen></iframe>",
    "provider_name": "Vimeo",
    "provider_url": "https://vimeo.com/",
    "type": "video",
    "uri": "/videos/123456789",
    "version": "1.0",
    "video_id": 123456789,
    "width": 2048

Due to privacy reasons, the video ID was replaced by 123456789.
To test this, create a Vimeo video, set the privacy settings to "Who can watch?" to "Anyone" and "Where can this be embedded?" to "Specific domains" and choose your domain.

The API docs (https://developer.vimeo.com/api/oembed/videos) state the following:

NOTE: In the case of a video with domain-level privacy, 
the oEmbed request returns a simplified response containing the embed code only and no private metadata. 
To get the complete response, send the Referer header along with the request, 
and set its value to the video's whitelisted domain.

This is the case here. As you see, the JSON response contains no title.

When adding the video in the TYPO3 filelist, it will be successfully saved as ".vimeo" ($oEmbed['title'] . '.' . $fileExtension in \TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\AbstractOEmbedHelper::transformMediaIdToFile):

            if (!empty($oEmbed)) {
                $fileName = $oEmbed['title'] . '.' . $fileExtension;
            } else {
                $fileName = $mediaId . '.' . $fileExtension;

Actually, $oEmbed['title'] is undefined (!isset()) here, but the script only checks if $oEmbed is empty, which is insufficient. (This is a bug on its own!)

Following, a success flash message is shown, but the file will not be visible because of the default filterHiddenFilesAndFolders filter defined in defaultFilterCallbacks.
When trying to create the vimeo file once more, \TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\AbstractOnlineMediaHelper::findExistingFileByOnlineMediaId() will find the existing file, but not tell the user about it.
So again a green success flash message is shown. (This is another bug. The user should be informed that this video exists already in the folder.)

The actual solution, however, would be to send a referer header with the hostname, like:

curl 'https://vimeo.com/api/oembed.json?width=2048&url=https%3A%2F%2Fvimeo.com%2F123456789' -H 'Referer: https://example.com' | python -m json.tool 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   950  100   950    0     0   4166      0 --:--:-- --:--:-- --:--:--  4166
    "account_type": "pro",
    "author_name": "Redacted",
    "author_url": "https://vimeo.com/redacted",
    "description": "",
    "domain_status_code": 200,
    "duration": 235,
    "height": 1152,
    "html": "<iframe src=\"https://player.vimeo.com/video/123456789?app_id=122963\" width=\"2048\" height=\"1152\" frameborder=\"0\" title=\"Redacted video title\" allow=\"autoplay; fullscreen\" allowfullscreen></iframe>",
    "is_plus": "0",
    "provider_name": "Vimeo",
    "provider_url": "https://vimeo.com/",
    "thumbnail_height": 540,
    "thumbnail_url": "https://i.vimeocdn.com/video/redacted_960.jpg",
    "thumbnail_url_with_play_button": "https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2Fredacted_960.jpg&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png",
    "thumbnail_width": 960,
    "title": "Redacted video title",
    "type": "video",
    "upload_date": "2019-01-01 00:00:00",
    "uri": "/videos/123456789",
    "version": "1.0",
    "video_id": 123456789,
    "width": 2048

You can see the full response being sent due to the -H 'Referer: https://example.com' header. (For testing, use the hostname you applied as embed restriction in the vimeo privacy settings.)

Only now is a title sent, and $oEmbed['title'] . '.' . $fileExtension no longer results in .vimeo but, in this example case, in Redacted video title.vimeo.

A little gotcha:
Unfortunately the filelist module does not "know" which of the TYPO3 installation's possibly many domain records match the video's privacy restrictions.
Therefore, TYPO3 would have no choice but to try sys_domain records until the oEmbed request returns a video title.
Meaning: If only one of multiple sites within a TYPO3 installation is whitelisted for the video, then the video can be added.
Otherwise you might want to let the request fail or succeed with a warning to the user (using the video ID as filename and remaining unable to set a preview image (thumbnail).

Same in TYPO3 8 and 9.


#1 Updated by Susanne Moog 6 months ago

Hey, thanks for the detailed report.

Do you think you could prepare a patch for this and push it to our review system? See https://docs.typo3.org/typo3cms/ContributionWorkflowGuide/Index.html for more information.

Also available in: Atom PDF