Thursday, December 18, 2008

Google Friend Connect site authentication

OK. Here's the deal:

I want to use GFC to authenticate users for my site.

It sounds like it should be doable, right? I think it is, but at the moment it's kind of hard. In fact it's so hard (or I'm so soft) that I haven't been able to do it (yet). Let recap a bit what it is GFC (Google Friend Connect) does;

1. If you enable GFC for your site, you can add GFC widgets which let people comment and rate the page you add the widgets to and interact in various ways. You can also add any custom OpenSocial widget you like (AFAIK)

2. One of the widgets you must have is the login widget which let anybody 'join' your site. When they do so, Google open up a separate window which let them choose their method of authentication; Google, Yahoo, OpenId, et.c., with various suboptions in Google's case).

3. Now Google keeps track of unique users that act on the widgets on your site, let them unjoin, log in and out, and so on.

4. The original identity provider (Google, Yahoo, et.c.) is still used as always for changing password, user info, et.c.

This is really great. The immediate thought when realizing how things work is that you want somehow to leverage this great new functionality that Google provide: To have a secure, authenticated site where you don't need to manage anyones identity, password changes, et.c.

So, I started trying to do so.

The first easy thing was to create a custom OpenSocial widget on my own site, that I pull in using the custom widget option on the 'social gadgets selection' on the GFC admin site; http://www.google.com/friendconnect .

What happens is that you let GFC generate a HTML snippet that loads an open social script from google, which in turn pulls in your script - through - google's proxy server. In any event, the script resides on a directory on your server, and get to land on you page (which was just recently in another directory) and can then suddenly utilize all GFC magic - check the id and name of current viewer, his/hers friend list, et.c. Neat.

But.

If you just post this info back to your server using standard Ajax - and trust the info you get - you're lost. How can you be sure that it really was your script that send that info? No, you need to make Google's GFC server send certified info back to your server about the current viewer.

Luckily enough, there's an OpenSocial call called (..) makeRequest, which makes an ajax call through the Container (Googl'es GFC servers, in this case, since Google/GFC is the Container. The Container would normally be LinkedIn, MySpace, Orkut, et.c.) to any given destination. For example your server, which actually hosts the page where the GFC widgets are hopping about.

http://code.google.com/apis/opensocial/docs/0.8/reference/gadgets/#gadgets.io.makeRequest

Is a great place to learn what can be done with this. For one thing, you can send back some good info. My simple OpenSocial script did just this, and made sure to begin in a nice and easy manner, not forcing any encryption, using AuthorizationType.NONE, like this;

...
...
var params = {};
params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.TEXT;
params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.NONE;
params[gadgets.io.RequestParameters.REFRESH_INTERVAL] = 5;
var url = "http://xxxxxxxxxxxxx";
console.log("calling url... '"+url+"'");
gadgets.io.makeRequest(url, reqcb, params);
};

function reqcb(data)
{
console.log("reqcb called....");
console.dir(data);
}
...
...

And this works well. Looking more carefully into the link above, one reads the following:

If opt_params[gadgets.io.RequestParameters.AUTHORIZATION] is set to gadgets.io.AuthorizationType.SIGNED, the container needs to vouch for the user's identity to the destination server. The container does this by doing the following:

  1. Removing any request parameters with names that begin with oauth, xoauth, or opensocial (case insensitive).

  2. Adding the following parameters to the request query string:

    opensocial_viewer_id
    Optional.
    The ID of the current viewer, which matches the getId() value on the viewer person object.
    opensocial_owner_id
    Required.
    The ID of the current owner, which matches the getId() value on the owner person object.
    opensocial_app_url
    Required.
    The URL of the application making the request. Containers may alias multiple application URLs to a single canonical application URL in the case where an application changes URLs.
    opensocial_instance_id
    Optional.
    An opaque identifier used to distinguish between multiple instances of the same application in a single container. If a container does not allow multiple instances of the same application to coexist, this parameter may be omitted. The combination of opensocial_app_url and opensocial_instance_id uniquely identify an instance of an application in a container.
    opensocial_app_id
    Optional.
    An opaque identifier for the application, unique to a particular container. Containers that wish to maintain backwards compatibility with the opensocial-0.7 specification may include this parameter.
    xoauth_public_key
    Optional.
    An opaque identifier for the public key used to sign the request. This parameter may be omitted by containers that do not use public keys to sign requests, or if the container arranges other means of key distribution with the target of the request.
  3. Signing the resulting request according to section 9 of the OAuth specification.


So, if I could use a SIGNED request instead, the GFC proxy servers would add all the info I need and crave for my service, especially a guaranteed identity of the current page viewer. Using this unique id in my tables gives me to power to associate this identity with anything I'd like on my site. Ok. Fine.

What happens when I use SIGNED? Well, the callback function always gets back the verbose, detailed and informative error message "404: Not found", in a JSON object, but still..

Now you might think that I don't know the first thing about public cryptography, signing requests and tossing certificates about in the rich and useful variety of almost-compatible formats the joyful and friendly cooperation between related companies in the beginning of this century gave rise to, but you'd be wrong.

I can't call myself an expert (any longer), but I have quite a good working knowledge of the above. the problem here is that the documentation makes references to the public certificate of the container, which the receiving service need to verify.

great, but the Container is GFC. Where's their certificate? Maybe this is obvious, I don't know. It isn't for me, anyway. Reading another page which digs deep in the OAuth spec, I find a links I've never seen before, which let me register sites with google and deploy their public certificates;

http://code.google.com/intl/sv-SE/apis/gdata/articles/oauth.html


Has some links that lead to the registration page for web-based applications;

https://www.google.com/accounts/ManageDomains

So I do just that, and use the OAuth playground;

http://googlecodesamples.com/oauth_playground/


to verify that things (seem to work).

Now, I'm not sure that my site, not being an OpenSocial container (surely!) need to register a certificate with Google, but just in case this was needed to make the SIGNED request work, I did so and played around with it.

No luck. The result stays the same; "404: not found". Great.

What I (and possibly **ALL** other site owners starting to use GFC) need, is some information. Anything of the below will be fine, if not else to give some info back to the community instead of the usual Google no-walling;

1. Here's a simple example which demonstrates how to write a simple OS gadget which post back the current viewers unique id and info.
2. Rick caught the flu last week and haven't had the time to write the example. We'll get on it in a couple of weeks.
3. We'll never give that information, stupid Englishmen! Go and boil your bottoms, sons of a silly person!
4. It's impossible to do what you want. Go back to bed.
5. Wow, that's an interesting idea. We hadn't thought of that! We'll get back to you..

Having emptied my reservoir of frustrated incompetence, I must end with stating the fact that despite all the trouble I've had in trying to get the site authentication to work, I've at least got my money's worth :)


[UPDATE]

Kevin Marks commented on one of my posts on the open social mailing list that GFC does not support signed requests at the moment. We got a number 4!! Yay! Thanks for the info, and let's hope that this gets added real soon.

Cheers,
PS

12 comments:

brian said...

Did you see this post on myspace...

http://developer.myspace.com/Community/forums/t/3272.aspx

A piece from a puzzle said...

In case you haven't found a solution for this problem yet: a nice trick I'm using is to register a RPC (remote procedure call) service in my web application (say, on what should be the login page), then make the authentication in the gadget itself, and on the callback make a request to the RPC with the authenticated user's data. Worked OK for me, maybe it'll be a good solution for your apps as well ;)

Peter Svensson said...

@A piece from a puzzle:
Certainly, if you want to manage authentication yourself, this is a viable option. However, the whole point of GFC is to let GFC do the authentication - it is what it is for.

I have thought about several variants that load a custom widget that passes data back to the server. However, you can't trust anything on the page to send you correct data.

What if your page has logged in correctly, and then some advertising on your site (for example) loads malicious JavaScript that send some made up authentication for some other user back to your server. Then you have no security at all.

The only solution is when Google unveil the new GFC/OS APIs that supposedly supports signed makeRequest access through the google GFC proxies. My guess is that they'll do so at Google I/O, in May.

Cheers,
PS

larsgberggren said...

Howdy Turbo!
Since I have been involved in creating a user service with OAuth connectivity, I was interested in how GFC is using OAuth. Nice to end up on your blog due to my searches.

/LG

Peter Svensson said...

@larsberggren: Sorry for not answering for so long. I've had a lot of stuff to do lately.. However, with the newly revamped API for GFC, everything is now almost too easy :)

Check out http://code.google.com/apis/friendconnect/serverside_integration.html for some good stuff on server-integration and OAuth.

Cheers,
PS

Chris said...

Any updates on this?

I'm running into trouble with an iGoogle plugin I'm developing. I also keep getting 404 - Not Found when using SIGNED for gadgets.io.RequestParameters.AUTHORIZATION.

Peter Svensson said...

@Chris: Hmm. I've been busy all over the place last months.. Could you send me code? I'll promise to see what I can do and to blog what I find. OK?

psvensson@gmail.com

Cheers,
PS

buddz said...

Wow thanks for all your reporting on this. I was considering using the GFC for authentication on a site I am currently working on and was looking for some info on it. You and your links answered all my questions. Thanks!!

gfh said...

Your Best Choice! wow power leveling and wow gold wow gold

Dean said...

greetings to all.
I would first like to thank the writers of this blog by sharing information, a few years ago I read a book called Real Estate Investment costa rica in this book deal with questions like this one.

niz said...

Hello .. firstly I would like to send greetings to all readers. After this, I recognize the content so interesting about this article. For me personally I liked all the information. I would like to know of cases like this more often. In my personal experience I might mention a book called Generic Viagra in this book that I mentioned have very interesting topics, and also you have much to do with the main theme of this article.

tonyeewu said...

Nike free run plus 2
Nike free women
Nike free 2011
Nike free run women
Nike free run plus
Nike free run shoes
cheap Nike free run
Nike free run 2011
Nike free run 2