アプリでGitHubAPIを使用する
<対象>
・OAuth認証のフローを知りたい
・GitHubAPIをつかいたい
GitHubでは、検索やリポジトリの読み書き、プルリクエストの生成・更新・削除などいろいろなAPIが提供されています。
GitHubAPI
これらは
アクセストークンなしでAPIを使用することもできるのですが、その場合はAPIでできることが一部制限されてしまいます。例えば、SearchAPI
には以下のような注釈があります。
Note: You must authenticate to search for code across all public repositories.
パブリックなリポジトリを対象に検索を実行するには認証が必要です
というわけで、APIの全機能を使うためにはGitHub認証が必要になるわけです。
本記事ではiOSアプリでGitHub認証しアクセストークンを取得するまで(OAuth認証の流れとアプリ側の実装)をまとめました!
OAuth認証のフロー
・事前準備
ここからGitHubのアプリを新規に作成します。
必要事項を記入し、完了するとClient ID
とClient Secret
が発行されます。
でここからがアプリ内での処理です。
① 認可リクエスト
GithubのAPIを使ったアプリのサービスを受けたいので、「認可リクエスト」を行う
→ WebViewなどで認証画面を表示する
→ ユーザーはGithubにログインし、アプリに代理アクセスすることを許可する(連携認証の許可)
→ GitHubからコールバック
→ GitHubから認証コードをレスポンスとしてもらう
② アクセストークン取得
もらったコードを使ってアプリはGithubの「アクセストークン交換場所 (Token Endpoint)」にアクセスします。
その際、認証コードを「アクセストークン」に変換する為に、アプリは事前の登録で取得したクレデンシャル(Client ID
とClient Secret
)で認証を受けます。 (クライアント認証)
正しく認証されると、コードと引き換えにアクセストークンをもらいます。
以上の流れは「コードフロー」と呼ばれ、基本的なOAuthのフローです。
アプリで実装してみる
流れがわかったので、実装に落とし込んでみます。
(以下ではライブラリとして、Alamofire, Swiftyjsonを利用しています)
① 認可リクエスト
let gitOuthUrl = URL(string: "https://github.com/login/oauth/authorize?client_id={
取得したクライアントID }&scope=public_repo")
let gitOuthRequest = URLRequest(url: gitOuthUrl!)
webView.load(gitOuthRequest)
上記ではwebView
で認可リクエストを送っています。
(scope=public_repo
はパブリックなリポジトリに対する読み書き権限を要求していることを示します。なくてもOKです。参考)
で、以下のように連携認証のためにログインが求められます。
ここでログインを実行するとコールバックURLが実行され、認証コードを取得できるので、それを取得する処理を書きます。
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
// 設定しているコールバックURLのスキーム、ホスト名で分岐処理
if navigationAction.request.url?.scheme == "yyokii", navigationAction.request.url?.host == "GithubSearchApp"{
dismiss(animated: true, completion: nil)
// 認証コード取得
let code = getQueryStringParameter(url: (navigationAction.request.url?.absoluteString)!, param: "code")
// ② アクセストークン取得処理
let githubAPIManager = GithubAPIManager.sharedManager
githubAPIManager.getAccessToken(code: code, completion: nil)
decisionHandler(WKNavigationActionPolicy.allow);
}
static func getQueryStringParameter(url: String, param: String) -> String? {
guard let url = URLComponents(string: url) else { return nil }
return url.queryItems?.first(where: { $0.name == param })?.value
}
ここで使用されるコールバックURLはGithHubでアプリ登録したときに設定したURLとなります。
コールバックURLが叩かれたときにクエリパラメーターに付与されている認証コードを取得しています。
② アクセストークン取得処理
/// アクセストークンを取得
///
/// - Parameter code: このコードとアクセストークンを交換
func getAccessToken(code: String!, completion: @escaping () -> Void) {
self.code = code
let url = "https://github.com/login/oauth/access_token"
// 受信可能なレスポンスデータのメディアタイプを指定
let headers = [
"ACCEPT": "application/json"
]
// 認証に必要な値を設定
let parameters: Parameters = [
"client_id": self.clientId,
"client_secret": self.clientSecret,
"code": self.code
]
Alamofire.request(url, method: .post, parameters: parameters, encoding: URLEncoding.default, headers: headers).responseJSON{ response in
switch response.result {
case .success:
let json = JSON(response.result.value!)
// アクセストークンを取得
let accessToken = json["access_token"].string
UserDefaults.standard.set(accessToken!, forKey: ACCESS_TOKEN)
completion()
case .failure(let error):
print(error)
}
}
}
ヘッダー、リクエストパラメーターを設定し、"https://github.com/login/oauth/access_token"
をPOST通信で叩きます。でそのレスポンスからアクセストークンを取得しています。
このアクセストークンを使用してAPIを叩くには、ヘッダーに
"Authorization": "token " + {取得したアクセストークン}
をつければOKです!!
おわり!!!