omniauthを読んでみる

version: [v1.6.1](https://github.com/omniauth/omniauth/tree/v1.6.1)
requestを捌いてる部分と、その先の処理部分を少し読んでみる．

omniauth, oauth自体についての説明は省略する．

# entry point
## strategyの宣言

> OmniAuth::Builder class gives you an easy way to specify multiple strategies. 

 ```ruby
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :developer unless Rails.env.production?
  provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
```

開発中のアプリケーション内でstorategyを宣言するときは， `OmniAuth::Builder#provider` でかく．

## lib/omniauth/builder.rb
https://github.com/omniauth/omniauth/blob/master/lib/omniauth/builder.rb#L47-L59

```ruby:L47-59
def provider(klass, *args, &block)
  # ...
  begin
    # omniauth-xxx gem の読み込み
    middleware = OmniAuth::Strategies.const_get(OmniAuth::Utils.camelize(klass.to_s).to_s)
  rescue NameError
    raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may 
  need to install an additional gem (such as omniauth-#{klass})."))
  end
end

args.last.is_a?(Hash) ? args.push(options.merge(args.pop)) : args.push(options)
# rack middleware の生成
use middleware, *args, &block
```

`OminAuth::Builder#provider` は　`omniauth-xxx` gem を読み込んで rack middleware を生成

# Rack middleware
## lib/omniauth/strategy.rb
rack middleware なので call から
https://github.com/omniauth/omniauth/blob/master/lib/omniauth/strategy.rb#L175-L190

```ruby:L175-190
def call!(env)
  # ...
  return mock_call!(env) if OmniAuth.config.test_mode
  return options_call if on_auth_path? && options_request?
  return request_call if on_request_path? && OmniAuth.config.allowed_request_methods.include?(request.request_method.downcase.to_sym)
  return callback_call if on_callback_path?
  return other_phase if respond_to?(:other_phase)
  @app.call(env)
end
```

各フェーズのリクエストをdispatchしてる
`mock_call` とか `options_call` は本質から少しそれるので省略．
`request_call` と `callback_call` を見てみる

## request_call

```ruby:L200-220
def request_call # rubocop:disable CyclomaticComplexity, MethodLength, PerceivedComplexity
  # ...
  if options.form.respond_to?(:call)
    log :info, 'Rendering form from supplied Rack endpoint.'
    options.form.call(env)
  elsif options.form
    log :info, 'Rendering form from underlying application.'
    call_app!
  else
    if request.params['origin']
      env['rack.session']['omniauth.origin'] = request.params['origin']
    elsif env['HTTP_REFERER'] && !env['HTTP_REFERER'].match(/#{request_path}$/)
      env['rack.session']['omniauth.origin'] = env['HTTP_REFERER']
    end
    request_phase
  end
end
```

### request_phase
抽象メソッド
https://github.com/omniauth/omniauth/blob/v1.6.1/lib/omniauth/strategy.rb#L313-L318

```ruby
# @abstract This method is called when the user is on the request path. You should
# perform any information gathering you need to be able to authenticate
# the user in this phase.
def request_phase
   raise(NotImplementedError)
end
```

[omniauth-oauth2](https://github.com/intridea/omniauth-oauth2)でoverwriteしてる
https://github.com/intridea/omniauth-oauth2/blob/464fcef6c0a5f1a7526b9701cec37f342ce57ae3/lib/omniauth/strategies/oauth2.rb#L47-L49

```ruby
def request_phase
  redirect client.auth_code.authorize_url({:redirect_uri => callback_url}.merge(authorize_params))
end
```

認証urlに飛ばしてredirect_urlに戻ってくる

## callback_call
https://github.com/omniauth/omniauth/blob/v1.6.1/lib/omniauth/strategy.rb#L222-L231 -> [callback_phase](https://github.com/omniauth/omniauth/blob/v1.6.1/lib/omniauth/strategy.rb#L359-L362) -> [call_app!](https://github.com/omniauth/omniauth/blob/v1.6.1/lib/omniauth/strategy.rb#L406-L408)

```ruby
def call_app!(env = @env)
  @app.call(env)
end
```

サービスからのcallbackを受け取ってアプリケーションに戻す

---

##### かんそう

かなりさらっとしてるからいつかもうちょいちゃんとよみたい