概要
多くのユーザーは、ユーザー名、覚えなければならないパスワード、迷惑メールに紛れるメールコードといった登録フォームで諦めてしまいます。KlugAuth なら、Apple で続けるか Google で続けるをタップするだけで完了です。
KlugAuth は、各プラットフォームのネイティブなサインインを表示します。iOS と macOS では Face ID / Touch ID 付きの Apple のシート、Android では Google 向けのアカウントシート(Credential Manager)、iOS と macOS の Google 向けにはシステムのサインインウィンドウです。プロバイダーのIDトークンをお客様の nonce とともに返し、サーバーでそのまま検証できます。さらに、アカウント削除時に連携を取り消すために必要な Apple の認可コードも返します(App Store ガイドライン 5.1.1(v))。
Google SDK は同梱されていません。iOS と macOS の Google サインインは、システムのブラウザシートで PKCE を用いた標準の OAuth フローを使用するため、拡張機能は小さく保たれます。
KlugAuth は、登録、サインイン、Apple または Google によるデバイスのログアウト確認のために、実証の場である当社のアプリの現行リリースで使われています。
機能
- 自己完結型:ANE 1つで完結し、コアライブラリや依存 ANE の追加は不要
- iOS 13 以降、macOS 10.15 以降、および Apple シリコン搭載 Mac 上の iPad アプリでの Sign in with Apple
- Android(Credential Manager)と iOS / macOS(システムのサインインウィンドウ、Google SDK 不要)での Sign in with Google
- IDトークン、ユーザーID、メールアドレス、氏名。更新と取り消しのための Apple 認可コード
- リプレイ攻撃対策のための nonce ヘルパー(Apple は SHA-256 を、Google は生の値を使用)
- 再訪ユーザー向けの Apple 資格情報の状態チェック(authorized / revoked)
- 成功、キャンセル、エラーのイベントを個別に提供。キャンセルは報告され、エラーとしては扱われません
対応プラットフォーム
Android での Sign in with Apple は、Apple の Web フローと小さなサーバーページで実現できます。プロジェクトの一環として提供可能です。isSupported(Apple)と isGoogleSupported で、デバイスが何を提供できるかをコードから判断できます。
はじめに
アプリケーション記述子に拡張機能を追加します:
<extensions>
<extensionID>com.klug.auth.KlugAuth</extensionID>
</extensions>
Sign in with Apple には、entitlement を追加します(iOS:記述子の Entitlements、macOS:署名時):
<key>com.apple.developer.applesignin</key> <array><string>Default</string></array>
Google では、Google Cloud コンソールで OAuth クライアントを作成します:Web クライアント(その ID が Android でのトークンの audience になります)、パッケージ名と SHA-1 を指定した Android クライアント、そして iOS と macOS 用の iOS クライアントです。
コード例
ボタンからサーバーまでの5つの完全なフローです。すべての呼び出しは即座に返り、結果は KlugAuthEvent として届きます。完全なドキュメント →
import com.klug.auth.KlugAuth; import com.klug.auth.KlugAuthEvent; var auth:KlugAuth = KlugAuth.getInstance(); var nonce:String = ""; // a fresh one for every attempt appleButton.visible = auth.isSupported; // iOS 13+, macOS 10.15+, iPad apps on the Mac googleButton.visible = auth.isGoogleSupported; // Android, iOS 13+, macOS 10.15+ auth.addEventListener( KlugAuthEvent.APPLE_SUCCESS, onAppleSuccess ); auth.addEventListener( KlugAuthEvent.APPLE_CANCELED, onCanceled ); auth.addEventListener( KlugAuthEvent.APPLE_ERROR, onError ); auth.addEventListener( KlugAuthEvent.GOOGLE_SUCCESS, onGoogleSuccess ); auth.addEventListener( KlugAuthEvent.GOOGLE_CANCELED, onCanceled ); auth.addEventListener( KlugAuthEvent.GOOGLE_ERROR, onError );
function signInWithApple():void { nonce = KlugAuth.generateNonce(); // 32 random bytes as hex, used once if ( !auth.signInWithApple( nonce ) ) // false: not supported, or a sheet is already open showMessage( "Sign in with Apple is not available." ); // your app function } function onAppleSuccess( e:KlugAuthEvent ):void { // the token carries SHA-256 of the nonce: the server hashes the raw value and compares sendToServer( "apple", e.identityToken, nonce, e.fullName, e.authorizationCode ); saveAppleUserID( e.userID ); // stable for this Apple ID; your app function // e.email and the names arrive only on the FIRST authorization; // the e-mail is always inside the identity token } // your app function: the server verifies the token and signs the user in function sendToServer( provider:String, idToken:String, rawNonce:String, name:String, appleCode:String = "" ):void { var vars:URLVariables = new URLVariables(); vars.provider = provider; vars.id_token = idToken; vars.nonce = rawNonce; vars.name = name; if ( appleCode != "" ) vars.code = appleCode; // lets the server revoke the link later var req:URLRequest = new URLRequest( "https://your.server/auth" ); req.method = URLRequestMethod.POST; req.data = vars; var loader:URLLoader = new URLLoader(); loader.addEventListener( Event.COMPLETE, onServerAnswer ); // your app function loader.load( req ); }
import flash.system.Capabilities; // Android: the WEB client ID, which is the token audience on your server. // iOS and macOS: the iOS client ID, used in the system sign-in window. var googleClientId:String = Capabilities.manufacturer.indexOf( "Android" ) >= 0 ? "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com" : "YOUR_IOS_CLIENT_ID.apps.googleusercontent.com"; function signInWithGoogle():void { nonce = KlugAuth.generateNonce(); // Google puts the raw value into the token if ( !auth.signInWithGoogle( googleClientId, nonce ) ) // false: no client ID, or already open showMessage( "Google sign-in could not start." ); } function onGoogleSuccess( e:KlugAuthEvent ):void { // e.userID is the account e-mail; names arrive every time sendToServer( "google", e.identityToken, nonce, e.fullName ); }
function onCanceled( e:KlugAuthEvent ):void { // the user closed the sheet: not an error, simply stay on the start screen } function onError( e:KlugAuthEvent ):void { if ( e.type == KlugAuthEvent.GOOGLE_ERROR && e.errorCode == "NO_ACCOUNT" ) showMessage( "Please add a Google account to this device first." ); // Android else showMessage( "Sign-in failed: " + e.errorMessage ); // e.errorCode for your log }
auth.addEventListener( KlugAuthEvent.APPLE_CREDENTIAL_STATE, function( e:KlugAuthEvent ):void { // e.state: authorized | revoked | notFound | transferred | unknown if ( e.state == "revoked" || e.state == "notFound" ) signOut(); // your app function: the user removed the app from their Apple ID }); var savedID:String = loadAppleUserID(); // stored after APPLE_SUCCESS; your app function if ( auth.isSupported && savedID != "" ) auth.getCredentialState( savedID ); // Apple only: iOS and macOS
API 概要
| KlugAuth.getInstance() | 唯一のインスタンスを返します。 |
| isSupported | Sign in with Apple が利用可能な環境(iOS、macOS)で true になります。 |
| isGoogleSupported | Sign in with Google が利用可能な環境(Android、iOS、macOS)で true になります。 |
| generateNonce() | 静的メソッド。新しいランダムな nonce(16進数の32バイト)を返します。1回だけ使用し、同じ値をサーバーに送ってください。 |
| signInWithApple(nonce) | Apple のサインインシートを開きます。開始できなかった場合(非対応、またはサインインがすでに実行中)は false を返します。 |
| signInWithGoogle(clientId, nonce) | Google サインインを開きます。Android:Web クライアントID、iOS / macOS:iOS クライアントID。開始できなかった場合は false を返します。 |
| getCredentialState(userID) | ユーザーがまだ認可されているかを Apple に問い合わせます。結果は APPLE_CREDENTIAL_STATE として届きます。iOS と macOS 向けです。 |
| KlugAuthEvent | identityToken, authorizationCode, userID, email, givenName, familyName, fullName, state, errorCode, errorMessage. |
イベント
| APPLE_SUCCESS | identityToken, authorizationCode, userID。email と氏名は最初の認可時のみ。 |
| APPLE_CANCELED | ユーザーがシートを閉じました。 |
| APPLE_ERROR | システムからの errorCode と errorMessage。 |
| APPLE_CREDENTIAL_STATE | userID と state:authorized · revoked · notFound · transferred · unknown |
| GOOGLE_SUCCESS | identityToken, userID(アカウントのメールアドレス), email, givenName, familyName。 |
| GOOGLE_CANCELED | ユーザーがシートを閉じました。 |
| GOOGLE_ERROR | errorCode と errorMessage。Android では、デバイスに Google アカウントがない場合に NO_ACCOUNT。 |
KlugAuth を購入
AIR アプリケーション1つ分の年間ライセンスで、12か月間のすべてのアップデートが含まれます。お支払い後、拡張機能、ActionScript ライブラリ、ドキュメントをメールでお送りします(通常は1営業日以内)。ライセンスと条件
動作要件
| AIR SDK | 51.x(HARMAN) |
| iOS | iOS 13 以降 |
| Android | Android 6 以降、Google Play services |
| macOS | macOS 10.15 以降 |
| Apple | App ID の Sign in with Apple capability |
| Google Cloud コンソールの OAuth クライアント |