OauthSwiftでRefreshing an Access Token
既存 Rails アプリに OAuth 認証を実装する - techiumでOAuth認証対応したWebアプリに対してトークンのリフレッシュを行う。
環境
- Swift 4.1
- Xcode Version 9.3 (9E145)
- 対向Webサービス
- 利用OSS
Refreshing an Access Token
リフレッシュの仕様については以下を参照。
RFC 6749 - The OAuth 2.0 Authorization Framework
refresh_tokenが必要なので取得する。
@refresh_token=nil
refresh_token無い
refresh_tokenの生成を有効化
Doorkeeper gem で OAuth 認可の仕組みをサポートしているが、refresh_tokenを有効にしていなかった。
config/initializers/doorkeeper.rb
を修正する。
# Issue access tokens with refresh token (disabled by default)
- # use_refresh_token
+ use_refresh_token
デフォルトのまま使ってたけどトークンの有効期限2時間でrefresh_tokenがdisableってどう使うんだよ(デフォルトのまま使うなよ
もう一度動作を確認。
$ irb
>> require 'oauth2'
=> true
>> client_id = 'hoge'
>> client_secret = 'fuga'
>> redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
=> "urn:ietf:wg:oauth:2.0:oob"
>> site = "https://fierce-wave-40771.herokuapp.com"
=> "https://fierce-wave-40771.herokuapp.com"
>> client = OAuth2::Client.new(client_id, client_secret, :site => site)
=> #<OAuth2::Client:0x00000000925b80 @id="hope", @secret="fuga", @site="https://fierce-wave-40771.herokuapp.com", @options={:authorize_url=>"/oauth/authorize", :token_url=>"/oauth/token", :token_method=>:post, :auth_scheme=>:request_body, :connection_opts=>{}, :connection_build=>nil, :max_redirects=>5, :raise_errors=>true}>
>> code = "foo"
>> token = client.auth_code.get_token(code, :redirect_uri => redirect_uri)
=> #<OAuth2::AccessToken:0x000000015c4120 @client=#<OAuth2::Client:0x00000000925b80 @id="hoge", @secret="fuga", @site="https://fierce-wave-40771.herokuapp.com", @options={:authorize_url=>"/oauth/authorize", :token_url=>"/oauth/token", :token_method=>:post, :auth_scheme=>:request_body, :connection_opts=>{}, :connection_build=>nil, :max_redirects=>5, :raise_errors=>true}, @auth_code=#<OAuth2::Strategy::AuthCode:0x00000000f3b380 @client=#<OAuth2::Client:0x00000000925b80 ...>>, @connection=#<Faraday::Connection:0x00000000f3b010 @parallel_manager=nil, @headers={"User-Agent"=>"Faraday v0.12.1"}, @params={}, @options=#<Faraday::RequestOptions (empty)>, @ssl=#<Faraday::SSLOptions verify=true>, @default_parallel_manager=nil, @builder=#<Faraday::RackBuilder:0x00000000f3abd8 @handlers=[Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp], @app=#<Faraday::Request::UrlEncoded:0x0000000156fc60 @app=#<Faraday::Adapter::NetHttp:0x0000000156fd00 @app=#<Proc:0x0000000156fdf0@/usr/local/rvm/gems/ruby-2.3.1/gems/faraday-0.12.1/lib/faraday/rack_builder.rb:152 (lambda)>, @connection_options={}, @config_block=nil>>>, @url_prefix=#<URI::HTTPS https://fierce-wave-40771.herokuapp.com/>, @proxy=nil>>, @token="3c123b2a51d798b1880f63d5629741ee48ae8f3b716025bd4c663dccb8c807ae", @refresh_token="361c8c16bad6f9bc27a4cd0c7a3d55e1ccfdcf0cb8ff293939a81604208007c3", @expires_in=7200, @expires_at=1526609633, @options={:mode=>:header, :header_format=>"Bearer %s", :param_name=>"access_token"}, @params={"token_type"=>"bearer", "created_at"=>1526602433}>
refresh_tokenも取れるようになった。
OauthSwift でリフレッシュ
やっと本題。
OAuth 2.0 Token Expiration · OAuthSwift/OAuthSwift Wiki
これを参考に組んでみる。
_ = oauthSwift.client.get(
URLString,
success: { (_) in
completion?(oauthToken, nil)
}, failure: { (error) in
self.refresh(completion: { (token, error) in
completion?(token, error)
})
})
refreshの実装は以下のような感じ。
private func refresh(completion: ((String?, Error?) -> Void)?) {
let keychain = Keychain(service: OauthRailsTutorial.keychainService)
guard let refreshToken = keychain[OauthRailsTutorial.oauthRefreshTokenKey] else {
completion?(nil, nil)
return
}
oauthSwift.renewAccessToken(
withRefreshToken: refreshToken,
success: { [unowned self] (credential, _, _) in
self.storeCredential(into: keychain,
credential: credential)
completion?(credential.oauthToken, nil)
}, failure: { (error) in
print(error)
completion?(nil, error)
})
}
これで、
取得済みのトークンが有効ならそのまま使用、期限切れならリフレッシュ
と言う実装ができた。
その他
今回作ったものはこちら