Previous Entry | Next Entry

glyph
Taken with slight modifications from Jeremy's comment here.


The problem:

1. Safari does not allow an iframe with a domain different from the domain of the main page to set cookies unless the user 'actively' navigates it, i.e. clicks a link.

2. Facebook apps using iframes are an instance of this - the main page is apps.facebook.com, and the iframe is some.developer.site.


The solution:

(Note: I use MainController for storing most static pages and the very rare random-shit page, like this. YMMV.)

1. app/controllers/application.rb

Somewhere that will get executed whenever a user loads the page normally (e.g. a universal before_filter), do:

cookies['safari_cookie_fix'] = 'cookie OK'


This will signal to the page that the cookie has been set successfully.

2. app/controllers/main_controller.rb

  session :off, :only => :set_cookie

  def set_cookie
    cookies['safari_cookie_fix'] = params[:_session_id]
    redirect_to params[:redirect_to] and return
  end


This will get automatically posted to if the cookie did NOT get loaded (i.e. we're in the first page of a Safari iframe and Safari dropped our cookie in the trash).

session :off is because it doesn't yet have any cookie to get its session info from.

This action will basically just redirect onwards to the place you were supposed to be in the first place. The fact of redirecting will mean that Safari now thinks it's OK to set the cookie, and therefore, Rails' automagic session cookie setters will work too.

Actually setting the cookie is AFAICT superfluous but helpful for debugging.


3. config/routes.rb

map.safari_cookie_fix "safari_cookie_fix", :controller => 'main', :action => 'set_cookie'


Convenience.


4. app/views/layout.html.erb

Somewhere in your body (preferably high up, so it gets evaluated first and doesn't wait for rendering that will get preempted anyway), insert:

<script>
	function safariFixSession(sess_id, controller) {
		alert('no cookie found');
		var url = location.href;
		var url_with_redirect = controller + "?redirect_to=" + url;
		
		$$('body')[0].insert("<form id='safariFixSession'></form>");
		var f = $('safariFixSession')
		f.method = 'POST';
		f.action = url_with_redirect;
		var m = document.createElement('input');
		m.setAttribute('type', 'hidden');
		m.setAttribute('name', '_session_id');
		m.setAttribute('value', sess_id);
		f.appendChild(m);
		f.submit();
	} 

	if (document.cookie.indexOf("safari_cookie_fix") == -1) safariFixSession("<%= session[:session_id] %>", "safari_cookie_fix");
</script>


This will add a form to your page with the current session ID (if any) and automatically submit it to the controller we made in step 2.

Remember to remove the alert() line! It's very useful for testing but not so great for users. ;-)

Note that as I said above, the session ID passing seems to be completely unnecessary, so feel free to yank it. What is necessary is simply the auto-form-submit.

It's quite possible that Safari may consider this method a security problem and patch it. If so, I'll update this post w/ info if I have any. But Safari people: please make sure that app developers who are doing legitimate stuff aren't hurt - it just means that we'll have to redirect people to Firefox, hint hint.



I've tried this and it seems to work just fine.

Thanks to Jeremy & Will Henderson for the code!

Comments

( 5 comments — Leave a comment )
(Anonymous)
Jul. 21st, 2010 11:17 am (UTC)
Thanks for this
I was having the same problem with iframes/cookies/safari and your solution helped me create a .net version which fixed it.
(Anonymous)
Jan. 17th, 2011 03:20 pm (UTC)
Re: Thanks for this
Could you please share your .net solution with us? I'm not familiar at all with php or facebook. plssss
saizai
Jan. 17th, 2011 03:49 pm (UTC)
Re: Thanks for this
I don't use .net.
(Anonymous)
Aug. 13th, 2010 09:27 am (UTC)
thanks for the idea. for some reason in safari 5 my site seems to be able to set its own cookies (in iframe inside facebook) but facebook of course could not set its cookies using facebook connect.

I was able to figure this out, thanks to your idea though. posted the php solution on the facebook forum:

http://forum.developers.facebook.net/viewtopic.php?pid=257432#p257432

(Anonymous)
Dec. 10th, 2010 06:15 am (UTC)
Thanks!
This solved my problem (framed Facebook app with cookies when accessed by Safari).

Cheers!

Duncan
( 5 comments — Leave a comment )

Page Summary

Latest Month

August 2011
S M T W T F S
 123456
78910111213
14151617181920
21222324252627
28293031   

Tags

Powered by LiveJournal.com
Designed by Lilia Ahner