iOS 11 から追加された SFAuthenticationSession でシングルサインオン


※iOS 12 で SFAuthenticationSession は Deprecated になりました。今後は ASWebAuthenticationSession を使いましょう!
https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession

以下の記事にある SFAuthenticationSessionASWebAuthenticationSession に適宜読み替えてください。


下記の @glayash さんによる記事でも書かれていますが、iOS 10 までは Safari と SFSafariViewController の認証情報が共有されていました。

iOS 11 / Android O 時代のアプリ認証 - Qiita

しかし、iOS 11 からはそれぞれ独立した Cookie ストレージを持つように仕様が変更されました。

そこで iOS 11 beta 3 からは Safari の認証情報を共有できる SFAuthenticationSession というクラスが登場するのですが、この記事ではその使い方を説明したいと思います。

実行環境

  • Xcode 9.2

準備

今回は foursquare にログインしてみます。予め Foursquare 開発者サイト からアプリを新規登録し、CLIENT_ID と Redirect URI を取得しておきます。Redirect URI には fsoauthexample://authorized を設定してください。

実装手順

Xcode を起動し、適当なサンプルプロジェクトを作ります。
プロジェクト名は何でもいいです。

URL Schemes の設定

2017.8.8 追記:SFAuthenticationSession 初期化時に引数でスキームを指定する場合、この設定は不要です

fsoauthexample:// でアプリが立ち上がるように設定しておきます。

実装

SafariServices をインポートします。

import SafariServices

引数 url に認証用のURLを指定して、SFAuthenticationSession を呼び出します。

let url = URL(string: "https://ja.foursquare.com/oauth2/authenticate?client_id=
(YOUR_CLIENT_ID)&response_type=token&redirect_uri=fsoauthexample://authorized")!
self.session = SFAuthenticationSession(url: url, callbackURLScheme: nil) { url, error in
    print(url)
    // fsoauthexample://authorized#access_token=XXXXXXXXXXXXXX
}
session?.start()

※Xcode 9 beta 3 の時点では引数 callbackURLScheme に何を指定しても挙動が変わりませんでした(詳しい方いましたら教えてください)。

2017.8.8 追記:Xcode 9 beta 5になって、ようやく挙動に変化が現れました。callbackURLScheme にスキームを指定しておけば Info.plist への指定が不要になります。

start() メソッドを実行すると「アプリがSafariの情報を使うけど問題ない?」的なアラートが表示された後、 SFSafariViewController のような画面(本記事では「ログイン画面」と呼ぶことにします)がモーダル表示されます。

すでに Safari で Foursquare にログイン済みの場合は即座に redirect url(fsoauthexample://authorized)にリダイレクトがかかり、そのタイミングで completionHandler が実行されます。
未ログインの場合は、IDとパスワードを入力する通常のログイン画面が表示されます。ログインが成功すると、redirect url にリダイレクトがかかり、そのタイミングで completionHandler が実行されます。

completionHandlerurl にはリダイレクト先の URL がセットされているので、ここから access_token を取り出すことができます。

fsoauthexample://authorized#access_token=XXXXXXXXXXXXXX

completionHandler が実行されるタイミングでログイン画面は自動的に閉じますが、cancel() メソッドを呼ぶことにより、意図したタイミングでログイン画面を閉じることもできます。

これで SFAuthenticationSession によるシングルサインオンが完了しました。

サンプルコード

リンク