Twitter OAuth Strategy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Warden::Strategies.add(:oauth) do
  def authenticate!
    if params.include?('oauth_token') && credentials.authenticate!(params['oauth_token'])
      session.delete(:credential)
      success!(credentials)
    end

    redirect!(credentials.authentication_url)
  end

  def credentials
    @credentials ||= Credential.get(session[:credential] ||= Credential.create.id)
  end
end

Make sure to add this in your init.rb or equivalent

1
2
3
4
5
Merb::BootLoader.after_app_loads do
  Warden::Manager.serialize_into_session {|cred| cred.to_s }
  Warden::Manager.serialize_from_session {|id| Credential.get(id) }
end

And in your rack.rb or equivalent

1
2
3
4
use Warden::Manager do |manager|
  manager.default_strategies :oauth
end

credential.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
require 'oauth' # ~> oauth-0.3.2

class Credential
  include DataMapper::Resource
  extend Forwardable

  CONSUMER_KEY    = Merb::Config[:oauth][:consumer_key]
  CONSUMER_SECRET = Merb::Config[:oauth][:consumer_secret]

  property :id, DM::UUID, :nullable => false, :default => lambda { ::UUID.timestamp_create }, :index => true, :key => true
  property :access_token,   String, :length => 64
  property :access_secret,  String, :length => 64
  property :request_token,  String, :length => 64
  property :request_secret, String, :length => 64
  property :status,         Enum[:authenticated, nil]
  property :account_id,     Integer

  belongs_to :account

  def_delegators :id, :to_s
  def_delegators :request, :authorize_url

  def authenticate!(token)
    if token == self.request_token && verified?
      update(:status => :authenticated)
    end
  end

  def authentication_url
    authorize_url.gsub('authorize', 'authenticate')
  end

  def authenticated?
    self.status == :authenticated unless status.nil?
  end

  #TODO: you probably want to add more verification yourself
  def verified?
    !access.nil?
  end

  private

  def consumer
    @consumer ||= OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, :site => 'http://twitter.com')
  end

  def request
    @request ||= if request_token.nil? || request_secret.nil?
      request = consumer.get_request_token
      request if self.update(:request_token => request.token, :request_secret => request.secret)
    else
      OAuth::RequestToken.new(consumer, request_token, request_secret)
    end
  end

  def access
    @access ||= if access_token.nil? || access_secret.nil?
      access = request.get_access_token
      access if update(:access_token => access.token, :access_secret => access.secret)
    else
      OAuth::AccessToken.new(consumer, access_token, access_secret)
    end
  end
end