Rubyでgemを使わずに、twitterのアクセストークンを取得

#Ruby(rails)でアクセストークンを取得する際の大まかな流れ

**1. アプリ登録時に発行されたAPI_KEY、API_SECRETを使って、リクエストトークンを発行する**

**2. リクエストトークンをパラメーターにして、twitterの認証画面にリダイレクトする**

**3. ユーザーがリダイレクト先でアプリを認証**

**4. 認証完了後、パラメーターにoauth_tokenとoauth_verifierを持って、帰ってくる**

**5. アプリ登録時に発行されたAPI_KEY、API_SECRET、4で手に入った値を使ってアクセストークンを取得する**

以上となります。

#ソースコード
エラーハンドリングとか、かなり雑です。参考程度にご利用ください。
「とりあえず動け」な発想の元に作ったのでメソッド化とか無視してます。

```lang:get_access_token.rb

  def index
    request_tokens = get_request_token
    oauth_token = request_tokens["oauth_token"]
    redirect_url = "https://api.twitter.com/oauth/authenticate?oauth_token=#{oauth_token}"
    session[:oauth_token] = oauth_token
    redirect_to redirect_url
  end
  
  def callback
    oauth_token = params[:oauth_token]
    oauth_verifier = params[:oauth_verifier]
    denied = params[:denied]
    if denied.present?
      render text: "Procedure canceled."
      return
    end
    if session[:oauth_token].blank? || session[:oauth_token] != oauth_token
      render text: "oauth_token is not matched."
      return
    end

    res = get_access_token(oauth_token, oauth_verifier)
    res_oauth_token = res["oauth_token"]
    res_oauth_token_secret = res["oauth_token_secret"]
    res_user_id = res["user_id"]
    screen_name = res["screen_name"]
    x_auth_expires = res["x_auth_expires"]
    str = "res_oauth_token: #{res_oauth_token}, res_oauth_token_secret: #{res_oauth_token_secret},"+
            "res_user_id #{res_user_id}, screen_name #{screen_name}, x_auth_expires #{x_auth_expires}"
    render text: str
  end

  def get_request_token
    api_key = 'hogehogehogehoge'
    api_secret = 'fugofugofugofugo'
    access_token = ''
    access_token_secret = ''
    callback_url = 'http://127.0.0.1:3000/callback'
    params = {
        "oauth_callback" => callback_url,
        "oauth_consumer_key" => URI.escape(api_key),
        "oauth_nonce" => URI.escape(SecureRandom.uuid),
        "oauth_signature_method" => URI.escape('HMAC-SHA1'), 
        "oauth_timestamp" => URI.escape(Time.now.to_i.to_s),
        "oauth_version" => URI.escape('1.0')
    }
    signature_key = "#{URI.escape(api_secret)}&#{URI.escape(access_token_secret)}"
    method = 'POST'
    request_url = 'https://api.twitter.com/oauth/request_token'
    request_oauth_header = sort_and_concat(params, "&")
    signature_data = "#{URI.escape(method)}&#{escape(request_url)}&#{escape(request_oauth_header)}"
    hash = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, signature_key, signature_data)
    signature = escape(Base64.strict_encode64(hash))
    params["oauth_signature"] = signature
    header_params = sort_and_concat(params, ',')

    twitter_uri = URI.parse(request_url)
    https = Net::HTTP.new(twitter_uri.host, twitter_uri.port)
    https.use_ssl = true
    https.verify_mode =  OpenSSL::SSL::VERIFY_NONE
    req = Net::HTTP::Post.new(twitter_uri)
    req["Authorization"] = "OAuth #{header_params}"
    https.set_debug_output $stderr
    res = https.request(req)
    #res.code + "/" +res.body
    param_hash = Hash.new 
    array = res.body.split('&')
    array.each { |e|
      param = e.split('=')
      param_hash[param[0]] = param[1]
    }
    return param_hash
  end

  def get_access_token(oauth_token, oauth_verifier)
    oauth_token_secret = session[:oauth_token_secret]
    if oauth_token_secret.blank?
      return "oauth_token_secret is not arrive in session."
    end
    
    api_key = 'hogehogehogehoge'
    api_secret = 'fugofugofugofugo'
    access_token = ''
    access_token_secret = ''
    params = {
        "oauth_consumer_key" => URI.escape(api_key),
        "oauth_nonce" => URI.escape(SecureRandom.uuid),
        "oauth_signature_method" => URI.escape('HMAC-SHA1'), 
        "oauth_timestamp" => URI.escape(Time.now.to_i.to_s),
        "oauth_token" => oauth_token,
        "oauth_verifier" => URI.escape(oauth_verifier),
        "oauth_version" => URI.escape('1.0')
    }
    signature_key = "#{URI.escape(api_secret)}&#{URI.escape(access_token_secret)}"
    method = 'POST'
    request_url = 'https://api.twitter.com/oauth/access_token'
    request_oauth_header = sort_and_concat(params, "&")
    signature_data = "#{URI.escape(method)}&#{escape(request_url)}&#{escape(request_oauth_header)}"
    hash = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, signature_key, signature_data)
    signature = escape(Base64.strict_encode64(hash))
    params["oauth_signature"] = signature
    header_params = sort_and_concat(params, ',')
    twitter_uri = URI.parse(request_url)
    https = Net::HTTP.new(twitter_uri.host, twitter_uri.port)
    https.use_ssl = true
    https.verify_mode =  OpenSSL::SSL::VERIFY_NONE
    req = Net::HTTP::Post.new(twitter_uri)
    req["Authorization"] = "OAuth #{header_params}"
    https.set_debug_output $stderr
    res = https.request(req)
    param_hash = Hash.new 
    if res.code == "200"
      array = res.body.split('&')
      array.each { |e|
        param = e.split('=')
        param_hash[param[0]] = param[1]
      }
    else
      param_hash["error_msg"] = res.body
    end
    return param_hash
  end

  def sort_and_concat(params, delimiter)
    params = params.sort
    str = params.collect{|k, v| "#{k}=#{v}"}.join(delimiter)
    return str
  end
  
  def escape(str)
    return ERB::Util.url_encode(str)
  end

```

#参考
[Twitter APIの使い方まとめ](https://syncer.jp/twitter-api-matome)を参考にして書いています。どこのサイトもgemを使って書いているので、助かりました！