Last week, for some reason, I had multiple requests for an example of ColdFusion and OAuth integration. I ended up creating quick demos for Facebook, LinkedIn, and Google. This week I'll be blogging each in turn in the hopes that these entries can help others. Today, I'm going to share the Facebook code.
Before I begin, I want to warn folks. I wrote this code very quickly. It is not optimized. Also, the person I was helping was on ColdFusion 8. So the code isn't exactly what I'd call up to date. Of course, it will run just fine with ColdFusion 10. I typically assume that folks take my code samples here as just that - code samples - but I wanted to be more clear that this code would probably not be exactly best practices.
To begin, ensure you have access to Facebook's Developer portal (developer.facebook.com) and create a new application.

You can call it whatever you want, but the name should reflect your site in some way. Users will see this when your app launches so make it familiar. You can ignore the other two options.
On the next page, make note of your App ID and App Secret:

Click on "Website with Facebook Login" and enter a value for your site. You can, and probably should, use a local domain. In other words, you can enter something under localhost. Obviously this will change to a production URL once you're done, but for testing, localhost is fine. For my testing I used: http://localhost/testingzone/cf8fb and clicked Save Changes.
That's it for the Facebook side. Now let's talk about the OAuth process in general. I'm not going to go very deep into this as OAuth has been discussed elsewhere and my focus here is to demonstrate a ColdFusion example, but at a high level, the process looks like this:
- Your site tells the user that you're going to send them to Facebook to authenticate/connect.
- You create a "special" link that includes some required crap in the URL. Along with the required crap, you will have some optional crap. So for example, many OAuth providers ask you to spell out exactly what you want to use from the user. I.e., how much private data you require. Your link will include that, and Facebook will then warn the user. I.e., "This site wants to take your lunch money, read your email, and have relations with your significant other."
- The user clicks and ends up at Facebook.com with a app-specific screen there. See the previous bullet point on how that screen may change.
- The user clicks Yes or No (or approve or whatever).
- Facebook sends you back to your site. In the URL will be a flag that you can check that will tell you if the user allowed your app. If they did, you will also have a special code.
- You take that code, make a request (using CFHTTP) to Facebook, to get a secret access token.
- This access token then allows you to get stuff. What stuff depends on what you asked for (see bullet point two).
That's it - roughly - and what's cool is that you will see this exact same (for the most part) process over my next blog entries as well.
With that in mind, let's look at the code. Again, I want to warn you this is a bit rough. First, the Application.cfc:
Obviously the app ID and app secret are removed above. The redirect URL will be used in a bit. Note that I've enabled session management as well. Now let's look at index.cfm.
There's two parts to this template. The first portion is run when you first get to the site and haven't connected to Facebook yet. I'm using a simple Session variable to track that. I provide a quick prompt and when clicked, I send the user to Facebook. Upon reflection, how I did this was kind of stupid. I could have just had the link in the original HTML link.
Speaking of the link, note the parts to it. client_id comes from our application settings. redirect_uri simply tells Facebook where to send the user when they OK/deny the connection. As I said, it is perfectly ok for this to be localhost during testing. The state variable is a security setting. I use a Session variable to store a UUID and ensure that the remote site (in this case, Facebook) sends back the same state. I could also use it for other things, like, well, state. Imagine I had 2 areas of my site where you could connect to Facebook. I could use this as a way to say, "I was in products", or "I was in music." Finally, the scope references what I'm asking for in terms of user privacy. Check Facebook's docs for more on what you can set in that regards.
Ok, so what happens when you click? Here is a screen shot.

Now let's look at redir.cfm, the main handler for the result from Facebook.
We begin by assuming that Facebook has return a code variable to us in the query string. We also validate the state variable I mentioned earlier. At this point, we need to get the Access Token from Facebook. This is done with a simple CFHTTP call. Note we pass back in the redirect URI. We aren't going back to redir.cfm again, this is just part of the security system.
If everything worked out ok, the result will be a string that looks like this:
access_token=AAAX&expires=5183804
That's where the string parsing code above comes into play. The access_token is what will give us access to the user's data.
If you return to the code sample above for index.cfm, you will notice that I've got a Facebook component tied to the user session. I can pass in the access token there and make use of it for future calls. I wrote this component very quickly. It doesn't have nice error handling or even pagination, but you can see an example of getting my profile as well as my friends.
I didn't spend much time on their API, but it seemed pretty darn easy to use.
You may be wondering - during testing - how do I get that permission screen to show up? You want to go to your Facebook Privacy settings, and then Manage Apps. This can be confusing because there is another link for this that brings you to your apps as a developer. You want to ensure you come here via your privacy settings, which will then help you manage your user app settings. Here's mine:

See my test app there on top? If you click the delete icon (x), you get this prompt:

This sounds like it may delete the app completely, but to be clear, this is user specific only. It is safe to confirm and test your application again.
Anyway, I hope this helps. I want to be clear that there's more involved here than what I've shown, but I wanted to share my sample app in the hopes others could use it.
Archived Comments
TY
YW :)
Great job on this Ray. Looking forward to reviewing the rest of the series.
great - just in time, I am working on a site that requires this stuff:)
Thanks for writing this series.. there is a project I've been itching to start using a site that utilizes oauth and I found it difficult to get started.
Part 2 was supposed to go live now, but I just blogged something else. It should be up around 4 though.
Great tutorial, thanks a lot :) I want connect this to database user - ie creating a registration form, is there any particular variable you would use to link the fb account to the database user? So they site can recognise them days later
Look at the result from the method called to get my own user details. It contains an ID. You could use that as a link to local tables. You may want to link it to username as well and ensure both match.
wondering if you are watching my google search keywords... reading my mind! thanks Ray.
Thanks. This is great. Looking forward to the rest of the series.
Thanks
looks too easy and any one can understand easly.
Thanks
Balriam
Hi Ray,
Thanks for this I have managed to hook it into my site perfectly for a facebook login. One thing im struggling with though is getting it to work on my iphone (same script) it throws up an element state is undefined in session error. any ideas what might be going on here? beating my head off of my wall hasnt helped and has just made my mrs angry :)
Finally got a chance to sit down and try this code. Ray as always you're amazing in how you A) seem to be able to read my mind about what I want to research and B) always explain things in such a way that you make it look so easy. Great job as always and thanks.
Mike, one issue a friend of mine ran into was using the wrong domain in the redir. By wrong I mean going from www.foo.com to foo.com. This caused the CF session to reset. Any chance that is happening to you? I assume not since you said it works ok outside of iPhone.
As always Ray, you are a scholar and a gent!.
That I think may be it, my redirect wasn't maintaining the www. and so it was dropping the session prior to firing the user to Facebook. forcing the www. seems to have resolved it nicely :)
Thanks!
Ray,
Thanks for the great post. I'm completely new to working with the Facebook API, and between your tutorial and the Graph Explorer I've been able to quickly and easily start getting data out of fb.
https://developers.facebook...
Nice! Will you write one for Twitter too?
Wasn't planning on it. ;)
Fantastic - I just grabbed Linked In - very clean code - no useless files - works like a charm. I'll give this one a shot too. Great work.
Thanks for the tutorial, Ray. It's taking between 4 and 6 seconds to execute the whole demo even when I run it again. Shouldn't it be taking about 1 sec? :-( BTW, when trying to submit a comment it kept telling me it's been marked as spam. I'm on my 12th revision...
Well, if you are logged in, the index.cfm page runs getMe and getFriends. Both of those are network requests that could be slow. You could wrap then with cftimer calls or just enabled debugging to verify. Typically you would cache those results and not rerun them every time.
Sorry about the spam blocker going overboard on you.
Works like a charm! However, what would be your method to automatically log in a user if their session expired but they're logged into Facebook? ...I might have found my answer: https://developers.facebook...
I believe if you autoforwarded them to the right link, they would auto bounce back.
For those that asked about Twitter Oauth I have put this together
http://cfjquery.com/blog/po...
Raymond, would you have any idea why index.cfm is throwing this error?
Could not find the ColdFusion Component or Interface facebook.
The error occurred in /web/cf.telegram.com/html/test/f... line 13
13 : <cfset session.fbAPI = createObject("component","facebook").init(session.fbaccesstoken)>
It means it can't "see" the facebook CFC. Did you copy it?
The Application.cfc file is in the same directory as index.cfm and redir.cfm. (Is there also a facebook.cfc?)
It is the last code sample above.
Gotcha. Thanks! (I REALLY appreciate it!)
Ray,
Thanks for the great start. I tried to work through the example but I think the code for your redir.cfm code is missing. Any chance you can repost?
Thanks,
Seth
The Gist that had the code borked out for some reason. I made a new Gist and replaced it above.
Thanks Ray!
Hi Ray! Thanks for the great tutorial.
I did a big and obvious copy and paste just to try and get your bear bones code working. When I login and get redirected back, I get the following error:
key [STATE] doesn't exist in struct (keys:urltoken,sessionid)
Seems state isn't defined in the session. Do you know how to solve this?
I'm using Railo if that makes a difference?
Thanks again!
Mikey.
Hmm. Well, it could be that you are losing your session when you leave the site and hit FB. Did you perhaps wait too long to click back?
Raymond,
I've been looking for this for a while. Very useful! Was able to get this working very quickly.
I'd like to ask an aggressively stupid question (as I've never dealt with a CFC in a session variable before): How does one invoke this from a .cfm? I see the dump, but I've been unable to use the invoke tag to parse out any of the information.
Thanks
If session.foo was a component, then it would simply be:
result = session.foo.someMethod()
Wow, you responded in two minutes! Thanks, Raymond!
Hi Ray,
I am still getting the error:
key [STATE] doesn't exist in struct (keys:urltoken,sessionid)
It seems that the session gets forgotten somehow. I might also add, that it IS initially set, because I am able to pass this to Facebook and then also have it returned in the URL.
However, when it comes to comparing the value of url.state to session.state ...it hits the error. Session is not defined.
Any idea how to solve this? I assume it happens because of a bug with cflocation?
I am using Railo.
Thanks,
Michael.
Yes, it does sound as if the session isn't sticking. Can you look at the cookies in the request before you access the session variable? Maybe do a quick cflog before you go and when you come back and see if they are changing.
Hi. I've got this working on one of my sites, thanks!. When i try to run it on another subdomain of the site (same CF server, changed the FB appids etc) the session.state doesn't stick and bombs out on the redir.cfm page.. Any ideas? The sites area almost identical, sessionmanagement set as well. etc..
thanks
@alessandro there's definitely an issue with CF when saving session variables and then doing a redirect. The session will be created and you can even test for it, but when you redirect and come back, it's gone! Happens to me on Railo. Seems like it's a common bug and intermitent at that. In theory, you don't NEED this state part, but it's more secure that way.
I have founding saving session.state like so works better than saving it as part of a deeper nested session.
For me, session.state works, but if I did, session.facebookStuff.state it does not.
It's a weird one.
If facebook user made logout? How clean session or to verify if facebook user session is valid?
The call to login won't work if the session is expired. Nor would the call for user details.
So, here's a fascinating error from CF/Facebook interaction. I created the world's simplest template that just outputs the URL variables sent to the page. This is the code:
<cfoutput>#testVar1#</cfoutput><br>
<cfoutput>#testVar2#</cfoutput><br>
When I run it through my server, it behaves normally:
http://myserver/facebook/wtf.cfm?testvar1=abc&testVar2=123
Returns: abc 123
This is the same server that I use for my FB application. So, when it's accessed in the correct way via facebook, It appends a slash ("/") to one of the variables like this:
https://apps.facebook.com/a...
Returns: abc 123/
Just curious if you think this is a result of FB messing with their server, or am I going crazy?
Thanks,
Andy
Not sure. Maybe they assume you aren't using URL params.
Hello. This process was working fine till some user notified me that they are getting errors.
Do you have any idea why this is happening all of a sudden?
struct
Charset [empty string]
ErrorDetail I/O Exception: peer not authenticated
Filecontent Connection Failure
Header [empty string]
Mimetype Unable to determine MIME type of file.
Responseheader
struct [empty]
Statuscode Connection Failure. Status code unavailable.
Text YES
isDefined(), in 2013, tut tut, Mr Cameron would have a field day with that :-)
Mr Cameron can suck it. ;) I don't get into the whole structKeyExists/isDefined thing. I just use what comes to mind first.
Great code, thanks. All of your code is working! Right now I'm trying to post a new post on my Facebook wall. I've put together the following code, but it is not giving the desired result. It's not posting and there is no error.
Any thoughts would be great!
http://pastebin.com/3PCYHrRK
BTW in my Pastebin are 2 possible solutions. Neither of them is working...
It's getting better. I now realise I have to ask permission to publish by extending the scope to publish_actions and publish_stream. I've also changed the cfhttparam from URL to FormField. Still no luck though...
When you changed it to ask for the right permission did you get a better error message?
Where is the code for the Facebook API? "createObject("component","facebook")"
In the code blocks above.
Nevermind, I see it.
Thank you for the post.
I have implemented facebook authentication for my application.I get the following error when I try to deploy the code in Production for Facebook authentication.
In Local testing environment, it works as a charm..
Note: I have made the encessary changes to the facebook app to point to the website
Error:
-------
The proxy server received an invalid response from an upstream server.
The proxy server could not handle the request GET /index.cfm.
Reason: Error reading from remote server
Can you please let me know anything you know about this?
It sounds like a network issue between production and Facebook. I'd check firewalls/etc on the production server.
Hi Ray, it looks like the scope is not retrieving the user's email, even when I enter "email" in the scope. I'm testing it with my own account which I know I'm allowing my email to be used.
I got the 'name' and 'id' of the user which allows me to fetch the picture, but I really need the email. Any suggestions?
You got me there - I haven't done FB+CF since this post I think. Maybe check the app settings to see if it is blocked there so that even if you request the scope you can't get it.
I checked the App Settings, email is allowed. There must be someone else keeping the email from being retrieved. I'll keep searching, thanks.
Please post back if you find it.
Did you guys ever discover a solution to this? I am getting the same issue.
Guess I should google a little better you can use this URL instead:
you have to ask for it now as part of requested permissions, it's no longer automatic.