Refused to display in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'
Categories:
Resolving 'Refused to display in a frame' with X-Frame-Options

Explore the 'Refused to display in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'' error, particularly in AngularJS applications integrating with Google OAuth, and learn effective strategies to resolve it.
The 'Refused to display in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'' error is a common security measure implemented by web servers to prevent clickjacking attacks. This error occurs when a website attempts to load content from another domain within an <iframe>, but the embedded content's server explicitly forbids this action. This article delves into understanding this error, especially in the context of AngularJS applications using ASP.NET Web API and integrating with Google OAuth, and provides practical solutions.
Understanding X-Frame-Options and SAMEORIGIN
The X-Frame-Options HTTP response header is used to indicate whether or not a browser should be allowed to render a page in a <frame>, <iframe>, <embed>, or <object>. Sites can use this to avoid clickjacking attacks, by ensuring that their content is not embedded into other sites. The SAMEORIGIN directive means that the browser will only allow the resource to be displayed in a frame if the top-level browsing context is the same origin as the resource itself. This is a crucial security feature, but it can sometimes interfere with legitimate use cases, such as integrating third-party authentication services like Google OAuth within a popup or iframe.

How X-Frame-Options: SAMEORIGIN Prevents Framing
The Challenge with Google OAuth and Iframes
When integrating Google OAuth into an AngularJS application, a common pattern involves opening the Google login page in a popup window or an <iframe>. However, Google's authentication pages are served with the X-Frame-Options: SAMEORIGIN header. This prevents them from being loaded directly within an <iframe> from a different origin, leading to the 'Refused to display' error. This is a security measure by Google to protect user credentials and prevent phishing attacks, as embedding the login page could potentially allow malicious sites to capture user input.
Solutions for Google OAuth Integration
The recommended approach for integrating Google OAuth (and most other OAuth providers) is to use a popup window or a redirect, rather than an <iframe>. This ensures that the authentication flow happens in a top-level browsing context, circumventing the X-Frame-Options restriction. When the authentication is complete, Google redirects back to a specified callback URL on your application, passing the authorization code or token.
For AngularJS applications, this typically involves initiating the OAuth flow by opening a new browser window (popup) using window.open(). Once the user authenticates, Google redirects to your callback URL. Your callback page then needs to communicate the authentication result back to the parent AngularJS application, often using window.opener.postMessage().
function openGoogleOAuthPopup() {
const width = 500;
const height = 600;
const left = (window.innerWidth / 2) - (width / 2);
const top = (window.innerHeight / 2) - (height / 2);
const authUrl = 'https://accounts.google.com/o/oauth2/v2/auth?' +
'scope=email%20profile&' +
'access_type=offline&' +
'include_granted_scopes=true&' +
'state=security_token%3D1%26url%3Dhttps://your-app.com/callback&' +
'redirect_uri=https://your-app.com/google-callback&' +
'response_type=code&' +
'client_id=YOUR_CLIENT_ID';
window.open(authUrl, 'GoogleAuthPopup', `width=${width},height=${height},left=${left},top=${top}`);
}
// In your callback page (google-callback.html/aspx):
// window.opener.postMessage({ type: 'oauth_success', code: 'YOUR_AUTH_CODE' }, 'https://your-app.com');
Example of initiating Google OAuth flow using window.open() in an AngularJS context.
X-Frame-Options. This is a security measure designed to protect users, and bypassing it could expose your users to clickjacking or other attacks. Always respect the security headers set by external services.Managing X-Frame-Options in ASP.NET Web API
While you cannot control Google's X-Frame-Options header, you might encounter similar issues with your own ASP.NET Web API endpoints if they are intended to be embedded. If your Web API is serving pages or content that you do want to embed in iframes from the same origin, you need to ensure your server doesn't send the X-Frame-Options header, or configure it appropriately. For content that should not be framed, especially if it handles sensitive user data, keeping X-Frame-Options: SAMEORIGIN or DENY is a best practice.
public class RemoveXFrameOptionsHeaderFilter : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
{
actionExecutedContext.Response.Headers.Remove("X-Frame-Options");
base.OnActionExecuted(actionExecutedContext);
}
}
// To apply globally in WebApiConfig.cs:
// config.Filters.Add(new RemoveXFrameOptionsHeaderFilter());
// Or for a specific controller/action:
// [RemoveXFrameOptionsHeaderFilter]
// public IHttpActionResult MyEmbeddableAction() { ... }
Example of removing the X-Frame-Options header in ASP.NET Web API. Use with extreme caution and only for content explicitly designed to be embedded securely.
X-Frame-Options accordingly on your server-side to enforce this security posture.1. Step 1
Identify the problematic iframe: Determine which specific <iframe> is causing the 'Refused to display' error.
2. Step 2
Check the embedded content's origin: Verify if the embedded content's origin matches your application's origin. If not, the SAMEORIGIN policy is likely the cause.
3. Step 3
Review the embedded content's server headers: Use browser developer tools (Network tab) to inspect the HTTP response headers for the embedded content. Look for the X-Frame-Options header.
4. Step 4
For third-party services (like Google OAuth): Switch from <iframe> embedding to a popup window (window.open()) or a server-side redirect flow for authentication.
5. Step 5
For your own content: If you control the server providing the embedded content, evaluate if it truly needs to be framed. If so, consider removing or modifying the X-Frame-Options header (e.g., by setting it to ALLOW-FROM uri if applicable, though this is deprecated, or carefully removing it for specific endpoints). Prioritize security and understand the risks of allowing framing.