Embed Nextcloud with iframe with login flow v2 authentication

Greetings,

We have a little problem on embedding Nextcloud into an iframe of another webapplication (Angular: http://localhost:4201).

The authentication method for nextcloud is: Nextcloud authentication method - Login Flow v2

We changed all the recommended headers within the .htaccess file:

Header always add Access-Control-Allow-Origin "http://localhost:4201"
Header always set Access-Control-Allow-Headers "origin, x-requested-with, content-type, authorization, depth, multistatus"
Header always set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS, PROPFIND"
Header always set Access-Control-Allow-Credentials "true"

<IfModule mod_headers.c>
  <IfModule mod_setenvif.c>
    <IfModule mod_fcgid.c>
       SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
       RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
    </IfModule>
    <IfModule mod_proxy_fcgi.c>
       SetEnvIfNoCase Authorization "(.+)" HTTP_AUTHORIZATION=$1
    </IfModule>
    <IfModule mod_lsapi.c>
      SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
      RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
    </IfModule>
  </IfModule>

  <IfModule mod_env.c>
    Header onsuccess unset Content-Security-Policy
    Header always set Content-Security-Policy "frame-ancestors 'self' http://localhost:4201;form-action 'self' http://localhost:4201;"

    Header onsuccess unset X-Content-Security-Policy
    # Header always set X-Content-Security-Policy "default-src 'self';base-uri 'none';manifest-src 'self';frame-ancestors *;"
    Header always set X-Content-Security-Policy "frame-ancestors 'self' http://localhost:4201;form-action 'self' http://localhost:4201;"

    Header onsuccess unset Referrer-Policy
    Header always set Referrer-Policy "no-referrer"

    Header onsuccess unset X-Content-Type-Options
    Header always set X-Content-Type-Options "nosniff"

    Header onsuccess unset X-Frame-Options
    # Header set X-Frame-Options "SAMEORIGIN"
    Header always set X-Frame-Options "allow-from http://localhost:4201"
    
    Header onsuccess unset X-Permitted-Cross-Domain-Policies
    Header always set X-Permitted-Cross-Domain-Policies "none"
    # Header always set X-Permitted-Cross-Domain-Policies "master-only" - not working

    Header onsuccess unset X-Robots-Tag
    Header always set X-Robots-Tag "noindex, nofollow"

    Header onsuccess unset X-XSS-Protection
    Header always set X-XSS-Protection "1; mode=block"

    SetEnv modHeadersAvailable true
  </IfModule>

  # Add cache control for static resources
  <FilesMatch "\.(css|js|svg|gif|png|jpg|ico|wasm|tflite)$">
    Header set Cache-Control "max-age=15778463"
  </FilesMatch>

  <FilesMatch "\.(css|js|svg|gif|png|jpg|ico|wasm|tflite)(\?v=.*)?$">
    Header set Cache-Control "max-age=15778463, immutable"
  </FilesMatch>

  # Let browsers cache WOFF files for a week
  <FilesMatch "\.woff2?$">
    Header set Cache-Control "max-age=604800"
  </FilesMatch>
</IfModule>

# PHP 7.x
<IfModule mod_php7.c>
  php_value mbstring.func_overload 0
  php_value default_charset 'UTF-8'
  php_value output_buffering 0
  <IfModule mod_env.c>
    SetEnv htaccessWorking true
  </IfModule>
</IfModule>

# PHP 8+
<IfModule mod_php.c>
  php_value mbstring.func_overload 0
  php_value default_charset 'UTF-8'
  php_value output_buffering 0
  <IfModule mod_env.c>
    SetEnv htaccessWorking true
  </IfModule>
</IfModule>

<IfModule mod_mime.c>
  AddType image/svg+xml svg svgz
  AddType application/wasm wasm
  AddEncoding gzip svgz
</IfModule>

<IfModule mod_dir.c>
  DirectoryIndex index.php index.html
</IfModule>

<IfModule pagespeed_module>
  ModPagespeed Off
</IfModule>

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{HTTP_USER_AGENT} DavClnt
  RewriteRule ^$ /remote.php/webdav/ [L,R=302]
  RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
  RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
  RewriteRule ^remote/(.*) remote.php [QSA,L]
  RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
  RewriteRule ^\.well-known/(?!acme-challenge|pki-validation) /index.php [QSA,L]
  RewriteRule ^(?:\.(?!well-known)|autotest|occ|issue|indie|db_|console).* - [R=404,L]

  RewriteCond %{REQUEST_METHOD} OPTIONS
  RewriteRule ^(.*)$ $1 [L,R=200]
</IfModule>

AddDefaultCharset utf-8
Options -Indexes
#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####

ErrorDocument 403 /
ErrorDocument 404 /
<IfModule mod_rewrite.c>
  Options -MultiViews
  RewriteRule ^core/js/oc.js$ index.php [PT,E=PATH_INFO:$1]
  RewriteRule ^core/preview.png$ index.php [PT,E=PATH_INFO:$1]
  RewriteCond %{REQUEST_FILENAME} !\.(css|js|svg|gif|png|html|ttf|woff2?|ico|jpg|jpeg|map|webm|mp4|mp3|ogg|wav|wasm|tflite)$
  RewriteCond %{REQUEST_FILENAME} !/core/ajax/update\.php
  RewriteCond %{REQUEST_FILENAME} !/core/img/(favicon\.ico|manifest\.json)$
  RewriteCond %{REQUEST_FILENAME} !/(cron|public|remote|status)\.php
  RewriteCond %{REQUEST_FILENAME} !/ocs/v(1|2)\.php
  RewriteCond %{REQUEST_FILENAME} !/robots\.txt
  RewriteCond %{REQUEST_FILENAME} !/(ocm-provider|ocs-provider|updater)/
  RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
  RewriteCond %{REQUEST_FILENAME} !/richdocumentscode(_arm64)?/proxy.php$
  RewriteRule . index.php [PT,E=PATH_INFO:$1]
  RewriteBase /
  <IfModule mod_env.c>
    SetEnv front_controller_active true
    <IfModule mod_dir.c>
      DirectorySlash off
    </IfModule>
  </IfModule>
</IfModule>

Also we made the recommended changed in ContentSecurityPolicy.php - just to ensure (some things are overwritten by .htaccess:

...
    protected $allowedFrameDomains = [
		'\'self\'',
		'localhost:4201',
		'devel-wk.ecmind',
	];
	
...

	/** @var array Domains which can embed this Nextcloud instance */
	protected $allowedFrameAncestors = [
		'\'self\'',
		'localhost:4201',
		'devel-wk.ecmind',
	];

	/** @var array Domains from which web-workers can be loaded */
	protected $allowedWorkerSrcDomains = [];

	/** @var array Domains which can be used as target for forms */
	protected $allowedFormActionDomains = [
		'\'self\'',
//      'localhost:4201', - has no effect
	];

...

This is a screen of the initial request - which works fine:

The current result is:

Expected in this case should be more something like a “Connect to your account” site with login-button to grant access i think.

Hopefully somebody has an idea what the problem could be, that an “Access denied” appears in iframe while the same (src-)URL is working as expected within a new window/tab.

Kind regards

Hello.

Your approach is rather strange. Normally, you trigger login flow V2 as you showed. That should not cause any trouble from the website as it is a pure API request. Then, you open the login URL in a new window/tab/pop-up. The user will provide his credentials and a token is generated in the background. You have the option to ask the server for the token once by polling from your webapp.

You might know this as a user from other pages when you pay via PayPal or credit card where you authorize the transaction in a separate browser environment.

You would not open the login page in an embedded iframe. That is against the idea of that login flow and might even impose security issues. This, you would have to change headers and coffee as described.

So, it basically it comes down to the question: why do you want to embed the login flow?
Did you misunderstand the documentation or is there some other requirements you did not mention?

1 Like

@christianlupus

Thank you for your response. We tried to implement a Nextcloud-Interface into a special Software which client works with Dashlets in iframes. Therefore it would be nice to have to Login/v2 flow Process embedded into an iframe instead of opening an explicit browser-window to grant the access.

The current solution we have implemented works fine, but opens a browser window outside of the software which can be a potential risk too.

Anyway thanks for your statement. We keep the current working solution.

1 Like