2019年 iOS アプリの Social Login 実装

## TL; DR.

以前は Twitter や Facebook の公式SDKを使うと、公式アプリに飛ばすことでシームレスなログイン体験を提供できました。ところが最近2社ともその挙動をサポートしなくなったので、OAuth を使った単純なログインを実装することになります。

## 前置き

会社で iOS アプリをフルスクラッチで書き直す決意をしました。そのため、2014年ごろからメンテしている Social Login 部分にもメスを入れて一から作り直しました。

iOSアプリは Facebook, Twitter, LinkedIn の連携をサポートしており、1:Nでユーザーは複数のアカウントを連携できます。サーバーは REST API を用いて Auth Token を受け取り、各社 API と通信してユーザーデータに変換し、データは SQL サーバーに保存されます。

### 各社のSDK

そもそもフルスクラッチで書き直しているのは、プロダクトの方向性を大きく変えるためであるので、使える部分はそのまま使おうと考え、Social Login はそのまま使えるだろう、と高をくくっていました。

#### Facebook

Facebook ログインを実装する場合、[公式ページ](https://developers.facebook.com/docs/facebook-login/ios) で [FBSDKLoginKit](https://github.com/facebook/facebook-objc-sdk) を利用せよ、と書いてあります。内部実装を見ると、`FBSDKLoginKit` は単純に `WKWebView` を使っているだけなので、Safari と Cookie 共有がされるわけでもなく、ユーザーは（Facebook アプリを持っていても）イチからログインすることになります。

使えなくはないですが、そこそこサイズの大きいSDKなので、Facebook ログインだけを実装するなら OAuth 2 を実装する方が良い判断だと思います。

#### Twitter

[Discontinuing support for Twitter Kit SDK](https://blog.twitter.com/developer/en_us/topics/tools/2018/discontinuing-support-for-twitter-kit-sdk.html) にあるように、そもそも [Twitter Kit SDK](https://github.com/twitter-archive/twitter-kit-ios) はメンテナンス終了しています。

実装を見ても UIWebView が内部に使われているので [Apple が UIWebView の使用を禁じる以上](https://developer.apple.com/documentation/uikit/uiwebview) 使わないことが賢明でしょう。（iOS7 以上では WKWebView に参照されるようなっていますが、そもそも UIWebView に参照を残すのはリスクになると思います。）

結局 Twitter ログインも OAuth を実装することになりますが、OAuth 1.0a を使う必要があります。ユーザーは、Twitter アプリを持っていても、イチからログインすることになります。

#### LinkedIn

LinkedIn は潔く公式 iOS SDK というものが存在しないので、OAuth 2 でログインを実装することになります。ユーザーは、LinkedIn アプリを持っていても、イチからログインすることになります。

## Sign in with Apple

「[ソーシャルログインを使うアプリは **必ず** Sign in with Appleを実装せよ](https://developer.apple.com/news/?id=09122019b)」とあるので、Sign in with Apple は必ず実装する必要があります。
[Adding the Sign In with Apple Flow to Your App](https://developer.apple.com/documentation/authenticationservices/adding_the_sign_in_with_apple_flow_to_your_app) にサンプルアプリがあり、このソースを読むとよくわかりますが、メールアドレスと氏名を取得する処理はかなり簡単にかけます。

そしてここが重要ですが、OAuth 2 と同じ方式で token が渡されるため、バックエンドから Authorization することができます。OAuth を用いたソーシャルログインを実装しているバックエンドは、大きく構成を変更する必要はありません。

## SaaS 

現在は SaaS と Serverless が大流行りしていますが、「アカウント管理も Saas に任せる」というソリューションがいくつも出ています。例えば [Auth0](https://auth0.com/), [Okta](https://www.okta.com/), [Amazon Cognito](https://aws.amazon.com/cognito/) などです。我が社はそもそも自前データベースにユーザーを保存していたので、あまり使ううまみはないのですが、ログイン処理の面倒なところをお任せできるのはありがたいかと思い導入検討しました。

### Auth0

データベース連携、値段、ドキュメントの見やすさから、導入するなら Auth0 だと社内合意をとった上で、技術検証しました。Okta や Amazon Cognito については調べていないので記述しません。

前述の通りドキュメントが充実しており、導入検証自体は見積もり通り進みました。

#### 挙動

Auth0 SDK を導入すると、Auth0 内の `WkWebView` が OAuth 処理を行います。つまり、Facebook などの認証処理自体は OAuth 認証を WebView で実装した処理と同じで、ユーザはメアド/パスワードをイチから入力することになります。

Auth0 SDK は **Auth0 の JWT トークン**を返却してくれます。Auth0に完全に認証処理を委譲する場合はクライアントがそのJWTトークンで認証処理を行えば良いです。今回の自社アプリはユーザーデータベースが内部にあるため、サーバーが Auth0 の JWT トークンから自社認証キーに変換する処理を加えました。

#### 問題

導入検証で問題になったのは Sign in with Apple で、導入は簡単に行えますが、こちらも WebView を介在して認証が行われるため、メアド/パスワードをイチから入力させられます。Sign in with Apple は **FaceID/指紋認証 を用いて素早くサインアップすることができる優れた新機能なのに**、それを失ってしまっては Apple もユーザーもうれしくありません。（ネイティブ実装で得た token を Auth0 の JWT トークンに変換することはできません。）

## 結論：iOS アプリに直接 OAuth を実装する

Auth0 を用いても、Sign in with Apple はネイティブ実装をした方が良いとわかりました。
Auth0 を Facebook, Twitter, LinkedIn に用いても良いのですが、別にただのWebViewによる OAuth 実装です。それならば OAuth を素直に実装した方が既存APIが使えるので最適と結論づけました。

OAuth 自体の説明は[一番分かりやすい OAuth の説明](https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be)が大変参考になりますが、アプリ側からすれば Authorization Token を取得してサーバーに投げつけるだけです。

OAuth 2 と 1.0a を実装するのはそれほど難しくないものの、エラー処理などを考えるとフレームワークを採用したかったので探しました。**[OAuthSwift](https://github.com/OAuthSwift/OAuthSwift) は使い勝手が良くおすすめです。**

仕組み上 `UIApplicationDelegate` や `Info.plist` を汚す必要は**なく**、コールバックを受け取るURLも自由に選択でき、`WkWebView` でも `SafariViewController` でも独自クラスを使うこともできます。（Doc に `UIApplicationDelegate`, `Info.plist` にコールバックを受け取るドメインを記載しろと書いてありますが、カスタムクラスでコールバックを受け取る分には必要ないのでスキップしましょう。）

# まとめ

Twitter や Facebook のログインを実装するなら、公式 SDK よりも OAuth ライブラリを使う方がすっきりします。

# 蛇足

そもそも Twitter, Facebook は数年前まで、無料で口コミを広げるマーケティングツールとして戦略の要になっていました。しかし昨今のプライバシー問題の影響もあり、各社 API 制限を行っており、将来的に publishing API （投稿に関わる機能）を制限する可能性が高いので、**Apple/Google アカウント連携の利便性を重視し、リファラル施策は別に考えていくというのが現実的だと思っています。**

ちなみに、Google Calendarを使うアプリなど、特殊な要件を満たしている場合は Sign in with Apple を適用する必要はありません。レビューガイドラインを参照してください。