This MOSTLY is working, so, here’s what I found when trying to connect to Facebook with OAuth. It needs some serious refactoring because a lot of this was done in an “investigative” trial and error way. It also looks like Facebook have improved their docs on this since I was first looking at them…
First, you need to initiate a connection:
get '/:blog_name/facebook/oauth/create' do
redirect "https://graph.facebook.com/oauth/authorize?client_id=##FACEBOOK API KEY##&redirect_uri=##CALLBACK URL##&scope=publish_stream,user_status,user_photos,user_about_me"
end
where ##FACEBOOK API KEY## = your applications API key (mine is a 32 digit hex value) and ##CALLBACK URL## = the URL that will be processing the next step. Also, the scope value let’s you get more access to the user’s account. Check their extended permissions doc for more info.
Next, you need to process what comes back from Facebook. I am stashing what comes back in the DB (the FacebookOauthToken model). Also using the Mechanize gem which is pretty silly. Some of the code below is specific to my app, so ignore those bits…
get '/:blog_name/facebook/oauth/callback' do
if !params['code'].blank?
url="https://graph.facebook.com/oauth/access_token"
client_id="client_id=##CLIENT ID##"
client_secret="client_secret=## CLIENT SECRET ##"
code="code=#{URI.escape(params['code'])}"
redirect_uri="redirect_uri=http://example.org/#{@blog.url_name}/facebook/oauth/callback"
url="#{url}?#{client_id}&#{client_secret}&#{code}&#{redirect_uri}"
begin
res=open(url)
rescue
flash[:error]="There was a problem connecting to Facebook"
redirect "/#{@blog.url_name}/"
end
read=res.read
access_token=CGI.parse(read)['access_token']
if !access_token.blank?
@blog.facebook_oauth_token = FacebookOauthToken.new(:access_token=>access_token,:blog_name=>params[:blog_name])
if @blog.save
begin
a=Mechanize.new
res=a.get("https://graph.facebook.com/me/?access_token=#{access_token}")
@blog.facebook_oauth_token.facebook_id=JSON(res.body)['id']
@blog.save!
rescue
flash[:error]="There was a problem getting information from Facebook"
redirect "/#{@blog.url_name}/"
end
flash[:notice]="Facebook connection created!"
redirect "/#{@blog.url_name}/"
else
flash[:error]="There was a problem saving Facebook connection"
redirect "/#{@blog.url_name}/"
end
else
flash[:error]="There was a problem making Facebook connection"
redirect "/#{@blog.url_name}/"
end
else
flash[:error]="There was a problem connecting to Facebook"
redirect "/#{@blog.url_name}/"
end
end
Where ##CLIENT ID## = your Application ID (mine is a 12 digit numeric value) and ## CLIENT SECRET ## = your Application Secret (mine is a 32 digit hex value).
Once you have an access_token you should be able to make calls to URLs like this:
"https://graph.facebook.com/me/?access_token=#{access_token}". The /me path is the connected user’s data and I’m grabbing their Facebook ID from the returned JSON for use elsewhere.
Posted: May 20th, 2010 | Author: jay | Filed under: Code | Tags: access token, api, client id, facebook, graph, graph.facebook.com, json, oauth | 1 Comment »
Application Scope
1
2
| # create the consumer...
consumer ||= OAuth::Consumer.new(KEY, SECRET, {:site => SITE, :authorize_path => PATH }) |
Session Scope
1
2
3
4
5
| # create the request token...
rt=consumer.get_request_token({ :oauth_callback => OAUTH_CALLBACK_URL })
# save the request token and secret in the session...
session[:r_token]=rt.token
session[:r_secret]=rt.secret |
User Scope (Model)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| # use session values to create the request token...
rt=OAuth::RequestToken.new(consumer, session[:r_token], session[:r_secret])
# grab the user data from the OAuth provider...
access_token=rt.get_access_token({:oauth_verifier=>params[:oauth_verifier]})
oauth_user_json=access_token.get(VERIFY_PATH).body
oauth_user=JSON.parse(oauth_user_json)
# create or find the the user (using twitter.com for the email address - could use some work)...
u=TwitterUser.first_or_create(:email=>"#{oauth_user['screen_name']}@twitter.com")
u.username=oauth_user['screen_name']
u.save!
u.oauth_tokens.all.destroy
u.oauth_tokens.new(:user_access_token=>access_token.to_yaml)
u.save!
# set the session user for future use...
session[:user]=u.id
...
# and when you need access to the OAuth provider again, use the access_token stored in the User model
u=User.first(:id=>session[:user])
access_token=YAML::load(u.oauth_tokens.first.user_access_token)
verify=access_token.get(OAUTH_PROVIDERS["https://twitter.com"][:verify_path]).body |
Posted: March 17th, 2010 | Author: jay | Filed under: Code | Tags: access token, application, consumer, gem, oauth, request token, ruby, session, sinatra, user | No Comments »
In my case it was an OAuth request token and when it was serialized it must have been larger than the cookie limit. Spent too much time on this.
Posted: March 17th, 2010 | Author: jay | Filed under: Code | Tags: 2k, oauth, rack, session | No Comments »
Summary of what’s going on with OAuth:
- create a OAuth consumer. Consumer is made up of:
- application key
- application secret
- the url and path to the OAuth provider
- create a request token:
- this makes a call to the provider
- the request token sends the callback URL to the provider
- it seems like this expires pretty quickly (at least with Twitter)
- therefore, I’ll probably hold this in a session
- once returned from the provider, you can redirect to the provider to complete the access
- once access is granted, the provider will return the user to the callback URL you sent
- create the access token:
- this makes a call to the provider
- the user is redirected from the provider to the callback URL
- a querystring variable –
oauth_verifier – is included with the callback URL
- the
oauth_verifier value is then sent back to the provider
- the provider then returns an access token
- the access token can hang around for a while and I’ll save that in the database attached to the User model
Posted: March 16th, 2010 | Author: jay | Filed under: Code | Tags: access token, consumer, key secret, oauth, provider, request token, token | No Comments »
And OAuth is winning
Posted: March 15th, 2010 | Author: jay | Filed under: Code | Tags: oauth, twitter | No Comments »
I’m now working on user creation process…
This was what I was trying to eliminate by using OpenID – but realistically, while OpenID may be suited to the problem “Allow access to a person visiting this site”, it isn’t well suited to the problems of “Use the supplied information to act as a user on this site”
The problem is this, OpenID allows for a federated login but doesn’t allow for basic user information (like an email address or name) which is critical to application usage to be passed back to the application. And while there is something called OpenID Simple Registration Extension (sreg), it doesn’t seem to be supported in ANY major OpenID providers.
This leaves OAuth or Facebook Connect. Both are better suited to replacing a the whole user creation / user model in that most of the necessary basic user information is available via either’s API. Additionally, information about the specific service that you’re connecting to is available. For example with Twitter’s OAuth, you have access to all of the friends associated with the Twitter account you’re connecting to.
Google, incidentally, is trying to mix the two together, which seems like a pretty good approach but I’m unaware of any other site using this mixed OAuth / OpenID thing at the moment.
So, in summary, I think I’ll start pursuing the OAuth approach. I will also probably build a Facebook Connect approach if time allows.
Posted: March 11th, 2010 | Author: jay | Filed under: Code | Tags: api, facebook connect, login, oauth, openid, sreg, user creation, user model | No Comments »
So it looks like I have to create the whole user model anyway. Blast.
I could use Facebook Connect or Twitter OAuth, but then users without a Facebook or Twitter account (they do exist- but mostly out of some *principal-based* logic) wouldn’t be able to grow moustaches for charity.
Posted: March 9th, 2010 | Author: jay | Filed under: Code | Tags: charit, facebook, facebook connect, moustaches, mustaches, oauth, openid, twitter | No Comments »