iOS
keychain
OAuth
Swift

iOSアプリでOAuth認証

iOSアプリでOAuth認証

AccessTokenの取得までは OAuthSwift で AccessToken 取得 - techium の通り出来たが、取得したトークンの保存だのといった取り回しが良く分からなかったので調べながら実装。

TL;DR

Keychain使いなさい、ということで。

今回作ったものはこちら。

kfurue/RxSwiftRailsTutorial at keychain-trial

環境

Store credential

ひとまずStore credential · OAuthSwift/OAuthSwift Wikiを参照。

かいつまんで言うとKeychainにストアしようね、っていうだけの内容だったので、kishikawakatsumi/KeychainAccess: Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS.を使って実装してみる。

KeychainAccess 導入

Carthageを使っているのでここの通りに。

現状最新はv3.1.1。特にハマるところは無いはず。

実装

動作確認目的なのでとりあえずViewController上で実装してみる。

    override func viewDidAppear(_ animated: Bool) {
        let keychain = Keychain(service: "kfurue.RxSwiftRailsTutorial-token")

        if keychain["oauthToken"] == nil {
            oauthswift.authorizeURLHandler = SafariURLHandler(viewController: self, oauthSwift: oauthswift)
            oauthswift.authorize(
                withCallbackURL: URL(string: "sample-app://oauth-callback")!,
                scope: "", state: "hoge",
                success: { credential, _, _ in
                    print(credential.oauthToken)
                    // OAuthSwiftで取得したトークンをKeychainにストアする
                    keychain["oauthToken"] = credential.oauthToken
            },
                failure: { error in
                    print(error.localizedDescription)
            }
            )
        }

    }

ストアしたトークンを取り出す。

        let keychain = Keychain(service: "kfurue.RxSwiftRailsTutorial-token")

        guard let token = (try? keychain.get("oauthToken")) as? String else {
            return
        }

取り出したトークンを使ってリクエストを投げてみる。

        SampleAppClientAPI.customHeaders["Authorization"]
            = "Bearer " + token
        feedTableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")

        viewModel.feeds.asDriver().drive(
            feedTableView.rx.items(cellIdentifier: "Cell"),
            curriedArgument: {_, micropost, cell in
                cell.textLabel?.text = micropost.content
        }).disposed(by: disposeBag)

動作確認完了。