A few months ago I wrote a few blog entries (see the links below) demonstrating how to use OAuth with Google, LinkedIn, and Facebook. I recently had a chance to work on those libraries again and I thought I'd share the updated code. I made some... questionable design decisions on those demos that I'd like to pretend were made by the Mirror Universe Ray instead.
The primary thing I've fixed in this update is to refactor the code to not be stored in the Session scope. I'm not sure what I was thinking. Now the code can persist in the Application scope. I also moved the logic to create the initial authorization URL into a method as well. In general, that's all that has changed, but I think this makes for a better set of code to use in future projects.
The components are still tag based (the user of this code is on ColdFusion 8), but that won't hurt. Honest. I hope these are helpful to you. For folks curious, these CFCs were used in an application that allowed login from each of the three providers. We then fetched the profile from the service and tried to aggregate as much data as possible into a single object that could be stored locally. Here is that code in question. This is from the file used as the redirection URL.
<cfif structkeyExists(url, "code") and structKeyExists(url, "state") and structKeyExists(session, "state") and url.state is session.state and structKeyExists(url, "type")>
<cfset user = structNew()>
<!--- switch based on type --->
<cfif url.type is "fb">
<cfset accesstoken = application.oauthApps.facebookAPI.getAccessToken(url.code)>
<!---
Now the idea is to get our data that we will use for userhookup/creation
--->
<cfset me = application.oauthApps.facebookAPI.getMe(accesstoken)>
<cfif structKeyExists(me, "first_name")>
<cfset user.firstname = me.first_name>
</cfif>
<cfif structKeyExists(me, "last_name")>
<cfset user.lastname = me.last_name>
</cfif>
<cfif structKeyExists(me, "gender")>
<cfset user.gender = me.gender>
</cfif>
<cfif structKeyExists(me, "email")>
<cfset user.email = me.email>
</cfif>
<!--- fb for pic is https://graph.facebook.com/ID/picture, not 100% sure this is kosher --->
<cfset user.picture = "https://graph.facebook.com/#me.id#/picture">
<cfif structKeyExists(me, "location") and isStruct(me.location)>
<cfset user.location = me.location.name>
</cfif>
<cfelseif url.type is "li">
<cfset accesstoken = application.oauthApps.linkedinAPI.getAccessToken(url.code)>
<!---
Now the idea is to get our data that we will use for userhookup/creation
--->
<cfset me = application.oauthApps.linkedinAPI.getMe(accesstoken)>
<cfif structKeyExists(me, "firstName")>
<cfset user.firstname = me.firstName>
</cfif>
<cfif structKeyExists(me, "lastName")>
<cfset user.lastname = me.lastName>
</cfif>
<cfset email = application.oauthApps.linkedinAPI.getEmail(accesstoken)>
<cfif len(email)>
<cfset user.email = email>
</cfif>
<cfelseif url.type is "g">
<cfset accesstoken = application.oauthApps.googleAPI.getAccessToken(url.code)>
<cfset me = application.oauthApps.googleAPI.getProfile(accesstoken)>
<cfif structKeyExists(me, "email")>
<cfset user.email = me.email>
</cfif>
<cfif structKeyExists(me, "given_name")>
<cfset user.firstname = me.given_name>
</cfif>
<cfif structKeyExists(me, "family_name")>
<cfset user.lastname = me.family_name>
</cfif>
<cfif structKeyExists(me, "gender")>
<cfset user.gender = me.gender>
</cfif>
<cfif structKeyExists(me, "picture")>
<cfset user.picture = me.picture>
</cfif>
</cfif>
<!--- Now do userhookup, sync --->
<cfdump var="#user#">
<cfelse>
oh poop
<cfabort>
</cfif>
Note that the actual "insert profile into db" portion wasn't done in this template - the client handled that part. But I thought the process was interesting and that others may find it useful.