Sign in with AppleをCordovaアプリで実装してみた際の記録です。
Sign In with Appleとは
- Apple IDでアカウント作成・ログインができる
- Touch ID/Face IDで認証できる
- 登録するメールアドレスをランダムにできる
実装手段は2つ
- Sign In with Apple JS
- AuthenticationServices (ネイティブ SDK)
とりあえずJS版をCordovaに埋め込むと・・
CordovaはWebView上で動作するので、Sign In with Apple JSで事足りるのでは?と思い、JS版をCordovaに埋め込んでみました。
とりあえず、UIWebVeiw上で動作させてみたところ、SignInボタンをタップすると、ブラウザに飛びました。
※ちなみに、生のUIWebViewだと無反応なので、そもそもUIWebViewは対応していないようです。
WkWebViewの場合は認証のモーダルが開きました。
ただ、CordovaのWebView内だとredirect先にページ遷移してしまうので、SPAで実装するCordovaアプリだとUX的にはネイティブSDK(AuthenticationServices)の方が良さそうです。
※redirect先がディープリンクならページ遷移せずにハンドリングできるかもしれませんが。
AuthenticationServices
AuthenticationServicesはiOS12から追加された認証サービスのフレームワークです。Sign in with Apple関連のAPIも含まれています。
AuthenticationServicesを使用してログインのリクエストすると、認証モーダルが表示されます(Face ID/Touch ID/パスワードの何れかで認証)
取得できる情報はID Token、認可コード、メールアドレス、ユーザーID、ユーザー名などです。
Cordovaプラグイン化
CordovaアプリにおいてJSからネイティブのSDKにアクセスするには、Cordovaプラグインを作成する必要があります。
そこで、作ってみました。
https://github.com/pscsrv/cordova-plugin-apple-login
以下サンプルコードです。
一通りのパラメーターは渡せるようにしています。(各パラメーターの詳細は、Githubに書いてあるAppleのドキュメントを参照してください)
SignInWithApple.request({
requestedScopes: [ SignInWithApple.Scope.Email ],
state: '...',
nonce: '...',
}).then((credential) => {
// ...
}).catch(error => {
console.error(error)
})
認証に成功すると、以下のようなオブジェクトが返ってきます。ほぼネイティブSDKのママです。
{
"authorizedScopes": [],
"identityToken": "eyJr.....K9NQ", // ID Token
"authorizationCode": "c5704....eV6sg", // 認可コード
"realUserStatus": 1,
"fullName": { // ユーザー名(最初の1回のみ取得可)
"namePrefix": null,
"givenName": "Daisuke",
"nameSuffix": null,
"middleName": null,
"familyName": "Kishino",
"nickname": null
},
"email": "XXX@privaterelay.appleid.com", // メールアドレス(最初の1回のみ取得可)
"state": null,
"user": "XXX" // ユーザーID
}
サーバー側
サーバー側はCordova特有のことはないですが、一応解説します。以下のような流れになります。
- 認可コードサーバー側に送る
- ID Tokenでも良いが、リプライ攻撃やID Tokenの検証を考えると、認可コードの方が安全
- Appleのtokenエンドポイントに投げて、ID Tokenを取得
- ID Tokenの署名や内容を検証して、OKなら会員登録/ログイン
以下フローです。オレンジ枠がAuthenticationServicesの担当箇所です。
ID TokenのPayloadは以下のようになっています。
{
"iss": "https://appleid.apple.com", // 発行者(Apple)
"aud": "jp.co.pscsrv.baassampleapp", // 発行先(App)
"exp": 1569548110, // 有効期限(10分)
"iat": 1569547510, // 発行時間
"sub": "XXX", // ユーザーID
"at_hash": "dP9t…OBDPA", // 認可コードのHash
"email": "XXX@privaterelay.appleid.com", // メールアドレス
"email_verified": "true", // ↑が検証済みか?
"is_private_email": "true", // ↑がPrivateか?
"auth_time": 1569547508, // ユーザー認証の時刻
"nonce": "XXX" // リプライ攻撃対策用のランダム値
}
注意点
- メールアドレスは初回だけ取得可能です(ユーザーがRevokeすると、再取得可能)
- ユーザー名はtokenエンドポイントから返ってこない(AuthenticationServices経由でのみ取得可能)
- client_secretはJWT(有効期限最大6ヶ月)
- PrivateメールアドレスはTeam ID単位に作成される
- ユーザーIDはRevokeされても変わらない。(メアドも変わらな
い。過去の記事など見ると変わるという記述もあるが・・)
サンプル
Cordovaプラグインの使用サンプルと、サーバー側実装のサンプルです。
Cordovaプラグインの使用サンプル
https://github.com/kishino/cordova-plugin-apple-login-sample
サーバー側実装
https://gist.github.com/kishino/281f13461e975c819161298d35b6de54
さいごに
実際にサンプルを使った感じ、iPhoneでのログインのUXはとても良いです。
CordovaでもSign in with Appleを実装して、より良いログイン体験を目指したいです!