CanvasIframe and RequireLogin (losing authentication)

Feb 19, 2010 at 9:23 AM

Hi,

I´m trying to create a CanvasIframe page but have some problems to get Facebook authentication to work using RequireLogin. I have setup a very simple project with two Web Forms (.aspx), a MasterPage and a custom PageBase.

The MasterPage extends Facebook.Web.CanvasIFrameMasterPage and my custom PageBase (Common.MyPageBase) extends Facebook.Web.CanvasIFrameBasePage.

I´m setting RequireLogin as follows (in the Page_PreInit() event handler of MyPageBase, this because the MasterPage doesn´t have one, right?)

 

namespace MyFacebookApp.Common
{
	public class MyPageBase : Facebook.Web.CanvasIFrameBasePage // System.Web.UI.Page
	{
		protected void Page_PreInit(object sender, System.EventArgs e)
		{
			// Facebook.Web.CanvasIFrameBasePage
			RequireLogin = true;

			// Facebook.Web.CanvasIFrameMasterPage
			//((Pages.Framework.MyMasterPage) this.Page.Master).RequireLogin = true;
		}
	}
}

Notice that I´ve tried setting the RequireLogin of CanvasIframeMasterPage as well.

 

Setting RequireLogin seems to work either way and I´m able to access the Facebook API and make my calls but only until I redirect or click to visit my second .aspx page (or reloading Default.aspx) where I get redirected back to the Facebook App. with the QueryString auth_token appended, the Connect URL are loaded again and I´m back at my startpage.

From http://apps.facebook.com/MyFacebookApp/ to http://apps.facebook.com/MyFacebookApp/?auth_token=e835bb1ac2e834d714017d2fbfbb3895

 

I´ve tried to set RequireLogin in a constructor of the MasterPage (as described in the sample, with same issues)

 

namespace MyFacebookApp.Pages.Framework
{
	public partial class MyMasterPage : Facebook.Web.CanvasIFrameMasterPage
	{
		protected MyMasterPage()
		{
			RequireLogin = true;
		}
	}
}

 

Are there any known issues with the CanvasIframe version or what am I doing wrong?

Would really appreciate any advice.

 

 

Feb 23, 2010 at 9:30 AM
Edited Feb 23, 2010 at 9:32 AM

Hello, its me again.

I´ve downloaded the source and debugged it together with my app. RequireLogin is successfully set in time but I´m still not able to move to any page on my site but Default.aspx (Connect URL) on the first authentication.

Should I be able to set RequireLogin on every page or just the landing page? If not how can I fully access the API?

 

While debugging the FDT source I noticed that none of the three if-statements in Facebook.Session.CanvasSession.LoadFromRequest() matched my page load(GET request).

 

if (!string.IsNullOrEmpty(sessionKeyFromRequest))
{ // S: QueryParameters (fb_sig_*) are only included/available at first load (auth).
	SetSessionProperties(
		sessionKeyFromRequest,
		long.Parse(inProfileTab ? HttpContext.Current.Request[QueryParameters.ProfileUser] : HttpContext.Current.Request[QueryParameters.User]),
		DateHelper.ConvertUnixTimeToDateTime(long.Parse(HttpContext.Current.Request[QueryParameters.Expires])));
}
else if (cachedSessionInfo != null && (HttpContext.Current.Request.HttpMethod == "POST" || !string.IsNullOrEmpty(authToken))) // only use cached info if user hasn't removed the app
{ // S: I dont understand the comment above. However, cachedSessionInfo is set, authToken isn´t but I´m trying to make a GET request.
	SetSessionProperties(cachedSessionInfo.SessionKey, cachedSessionInfo.UserId, cachedSessionInfo.ExpiryTime);
}
else if (!string.IsNullOrEmpty(authToken))
{ // S: authToken is not included or appended to my internal iframe links.
	session_info sessionInfo = new Api(this).Auth.GetSession(authToken);
	SetSessionProperties(sessionInfo.session_key, sessionInfo.uid, DateHelper.ConvertUnixTimeToDateTime(sessionInfo.expires));
}

 

 

SetSessionProperties() is never used and SessionKey, UserId and ExpiryTime is never set. This results in Facebook.Session.CanvasSession.Login() executing RedirectToLogin() that executs RedirectTopFrame(GetRedirect()) and this output a short JavaScript for redirect back to Facebook login page. As I´m still loggedin at Facebook I´m redirected to the app, my ConnectURL, I´m reauthenticated and back where I started.

 

Please help me understand how I can make my GET requests still keeping my authentication(cachedSessionInfo). Appending the authToken QueryString to all links is neither an option or a good solution.

 

Using FDT 3.01 and ASP.NET 3.5

Feb 23, 2010 at 8:49 PM

I was planning to write my own post but instead I will just say "ditto" to this.  I am having exactly the same issue.

 

Feb 24, 2010 at 9:21 AM

Nice to know that I´m not alone :)

 

Replacing line 126 in Facebook/Session/CanvasSession.cs

else if (cachedSessionInfo != null && (HttpContext.Current.Request.HttpMethod == "POST" || !string.IsNullOrEmpty(authToken))) // only use cached info if user hasn't removed the app

with

else if (cachedSessionInfo != null)

makes it possible for the API to use the cached session info even without the authToken or a POST.

 

By doing this I´m probably just replacing my problem with another, yet to find out though.

Could someone please explain the comment "only use cached info if user hasn't removed the app"?

Mar 2, 2010 at 11:53 AM

Hello,

I Have the same problem. 3 pages application with a single master page.
Did you found a good solution to make it works ?

Wil

 

Mar 4, 2010 at 3:34 PM

On your master page?  Then you should not call RequireLogin there, call at page PreRender.

Mar 14, 2010 at 5:17 AM

Hello

I am having the same issue, I have 4 pages with master page. I try with RequireLogin at page PreRender but don't work.

Have somebody any solution?

Apr 14, 2010 at 12:09 PM

I have similar issue.

So maybe someone (if not me) will post a solution.

 

 

Apr 15, 2010 at 1:54 PM

Not sure if I have right fix, but the problem lies in CanvasSession.HaveValidChachedSession.

This is workTiem 17178. So far I'm trying with this fix (not sure if it is correct one).

 private bool HaveValidCachedSession(CachedSessionInfo cachedSessionInfo, string authToken, string apiKeyRequestParam)
        {

            // Fix for 17178  
            // This is time as in pacific time 
            DateTime referenceTime = DateTime.Now.ToUniversalTime();
            int pacificZoneOffset = referenceTime.IsDaylightSavingTime() ? -7 : -8;
            referenceTime = referenceTime.AddHours(pacificZoneOffset);
            // END Fix for 17178


            if (cachedSessionInfo == null)
            {
                return false;
            }
            else if (referenceTime > cachedSessionInfo.ExpiryTime)
            //else if (DateTime.Now > cachedSessionInfo.ExpiryTime) //17178
            {
                return false;
            }
             // assume for now that all POST requests are valid, since they would have come from a GET just before now
            else if (HttpContext.Current.Request.HttpMethod == "POST")
            {
                return true;
            }
            // this is the case where the user removed the app, but now came back and wants to re-add it.
            // need to check apiKeyRequestParam, too, to make sure this link is coming from Facebook with proper request params,
            // instead of from within our app where request params are not expected
            else if (string.IsNullOrEmpty(authToken) && !string.IsNullOrEmpty(apiKeyRequestParam))
            {
                return false;
            }
            else
            {
                return true;
            }
        }

Apr 16, 2010 at 2:40 PM

Coud somebody please explain in a few words what this "auth_token" is and how is is appended to URL? Is it done by Facebook or by FDK? What does it have to do with canvas session?

Thanks in advance.

Kuba

Apr 27, 2010 at 6:36 PM
When you register the App you can only specify one canvas page url. When facebook loads your app in iframe it makes a call to the canvas page URL by appending some query params "fb_sig_XXX". Some of these "fb_sig_XXX" params include authorization token (used by Facebook .NET framework to verify that the request is originating from Facebook and not from any bogus site), userid etc. The .Facebook .NET framework needs these query params for initialization. If your canvas page has links to other pages, Facebook has no control over those. So when you click on the embedded links, there are no facebook query params and Facebook.NET framework cannot identify the user. I had a similar issue and I worked around it by appending the query params sent by Facebook to all my embedded URLs and it works like a charm. Now I don't know if its the recommended way...but it works. Hope it helps. Mahesh
Apr 27, 2010 at 6:47 PM

This is one way possible solution - but the session will run out of time (last 1 hour)

Other solution is to target all links to _top frame <a target="_top" ... />, this way facebook adds necesary arguments 

Apr 30, 2010 at 12:00 AM

I think i've got Idea what's going on. There are two problems:

First my problem was, that my Default.aspx doesnt require logging, only other Login.aspx does, and when I was accessing Login.aspx I was allaweays redirected to / (Default.aspx).

The thing is in login authorization process. Facebook gives away session only when you require user to login via redirecting him to login.php.  If user has added the application this is transparent as login.php imeniatly redirects him to your application. For iFrame pages this is done by inesrting JavaScript redirection. This then redirect to RedirectionURL created in CanvasSession line 215. The URL does NOT contain next parametr which should be set to actual URL! Because without it the user gets redirected to Canvas root / and Default.aspx which doesn't log him in.

(see http://wiki.developers.facebook.com/index.php/Authorization_and_Authentication_for_Canvas_Page_Applications_on_Facebook )

Second Session is then stored with it validity mark, but the session validity is processed by DateHelper which obviously transform the time badly,dont know whta time zone is used, but I is 0:50 here and my session "has expired" at 5pm yesterday - that is 8 hours bad.