{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreihf4yrbblnawg7d774mf3wmamiwmrxa4yxsq7yq5tpsjjryxnfrpq",
"uri": "at://did:plc:jixicdme7omicxzdn5nuvxzl/app.bsky.feed.post/3mhorpzsucue2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreifacydu2nj54mqt2ecua6z777tvp333nxbnqyj5ko64ecom3mz4qm"
},
"mimeType": "image/png",
"size": 47637
},
"path": "/entry/2026/03/23/android_sso",
"publishedAt": "2026-03-23T00:00:00.000Z",
"site": "https://blog.studysapuri.jp",
"tags": [
"@morayl",
"RFC8252(Best Current Practice)",
"GoogleのFAQ",
"ドキュメント",
"APIドキュメント",
"Android App Links",
"公式ドキュメント",
"Google Play署名",
"Microsoft Authentication Library",
"公式ページのチュートリアル",
"microsoft-authentication-library-for-android",
"サンプルアプリのリポジトリ",
"ライブラリの説明が書かれたページ",
"Android Microsoft Authentication Library configuration file",
"公式のよくある質問",
"詳しい説明",
"こちらのドキュメント",
"Resources and scopes",
"Prompt Enum",
"@Inject",
"@ApplicationContext",
"@Dispatcher"
],
"textContent": "# はじめに\n\nこんにちは。『スタディサプリ』 Android開発チームの@moraylです。\n\n『スタディサプリ 小学/中学/高校/大学受験講座』では昨年、Web/iOS/Androidでシングルサインオン(以下SSO)を実装しました。\n学校で利用しているユーザー向けで、ユーザーはApple/Google/Microsoftアカウントのうち学校に許可されたものを紐づけることで、各アカウントでログインできるようになります。\n今回は、Androidアプリにて各機能を実装したときの話をし、SSOについて得た知見を記せればと思っています。\n\nシーケンス図が出てきますが、Androidアプリにフォーカスするため、API以降の動作は省略したり簡易的に説明したりしています。\n設定ファイルやソースコードはサンプルを用いて解説します。\n文中の記載は実装当時のものなので、参考の際には最新の公式ドキュメントも合わせてご確認ください。\n\n\n# 全体方針\n\nSSOにはいくつか実装方法がありますが、社内のセキュリティ基準を鑑みて、以下の2パターンで行うことになりました。\n\n * クライアント向けの公式ライブラリを使用する\n * 自前で実装する\n\n\n\nまた、各ID Providerにログインを行う際には、WebViewではなく外部ブラウザを利用することにしました。 今回SSO実現のためにOpenID Connectを利用しますが、ネイティブアプリにおいて、そこで使われるOAuth 2.0認証は外部ブラウザで行うべきだからです。\n\n国際標準であるRFC8252(Best Current Practice)では、\n\n> OAuth 2.0 authorization requests from native apps should only be made through external user-agents, primarily the user's browser.\n\nと記されており、セキュリティやUX・互換性の観点から、ユーザーが利用するブラウザを使うべきと記載があります。\n\nまた、GoogleのFAQにも、\n\n> お客様のアプリの中に、認証に WebView を使用するものが含まれていますが、この方法は推奨されません。OAuth 2.0 リクエストに WebView を使用すると、アプリのセキュリティとユーザビリティの両方に悪影響を与えます。\n\nとあり、認証にWebViewを使用することは非推奨との記載があります。\n\n# Apple\n\n外部ブラウザを立ち上げて認証する方式を採用しました。\nApple公式のAndroid向けライブラリが存在せず、ドキュメントにも\n\n> To add Sign in with Apple to apps that don’t have access to the Sign in with Apple JS framework, you control the sign-in request manually.\n\n=「Sign in with Apple JSを使わない場合にはサインインリクエストを手動で制御する」とあります。\n\n\n## 画面遷移\n\nブラウザでAppleログインを開き、ログインが完了するとアプリが立ち上がり、プロフィール画面が開かれます。\n\n1.プロフィール画面でAppleを押す | 2.Appleログインのサイトが開く | 3.信頼するを押す\n---|---|---\n| |\n4.続けるを押す | 5.Appleが連携済みになる\n---|---\n|\n\n## シーケンス\n\nアプリにログインしているユーザーが、SSOを利用するために紐づけを行うシーケンスを説明します。\n\n\n大まかな流れとしては、以下になります。\n\n 1. アプリからAPIを使ってnonceを発行\n 2. ブラウザでApple認証を行う\n 3. ブラウザからアプリが起動される\n 4. アプリからAPIを使って紐づけを依頼(APIはnonceを検証する)\n\n\n\n以下でシーケンス図を使って詳しく説明します。\n\n#### 紐づけボタンを押す\n\nログイン済みのユーザーは、プロフィール画面でApple SSOの紐づけを行うことができます。\n紐づけの際、nonceを使っています。\n\nnonceとは、認証などの際に用いられる使い捨てのランダムなデータです。ユーザーの同一性を担保し、一度使ったら無効化することで、リプレイ攻撃やコードインジェクション攻撃を防ぐことができます。\nnonceを利用した場合、ID Tokenにはnonceが含まれるようになり、発行者は発行したnonceとID Tokenに含まれるnonceを検証することが出来ます。\n\n外部ブラウザを介す場合は「他人が発行したnonceが使われたカスタムURLスキーム」を受け取る可能性があります。要求したnonceをアプリに保存し、カスタムURLスキームを受け取った後にID Tokenと共にアプリに保存したnonceをAPIに送ることで、自分が発行したものだということを検証出来ます。\nそのため本シーケンスでは、要求したnonceをアプリに保存します。\n\n#### Apple認証\n\nnonceを保存した後、アプリはブラウザでAppleのログイン画面を開きます。\nURLとパラメーターはドキュメントに記載されています。 今回は、以下のパラメーターともに認証画面を開きます。\n\nパラメーター | 説明 | 指定内容\n---|---|---\nclient_id | clientの識別子 | アプリで定義したID\nredirect_uri | Apple認証が完了したときにAppleから叩かれるuri | 『スタディサプリ』のWebページを指定\nstate | フローの開始からコールバックまで任意の値を引き渡す仕組み | クライアント種別などのメタ情報を乗せる\nnonce | クライアントセッションと ID Tokenをひもづける値 | APIからもらったnonceを指定\nresponse_type | 認証タイプ | Authorization Code Flowなので\"code\"を指定\nresponse_mode | 認証完了後にどのようなレスポンスを返すか | \"form_post\"\n\nここで注意が必要なのがredirect_uriです。\n当初、Apple認証完了後にブラウザからアプリを開こうと考えていて、アプリのカスタムURLスキームを指定しようと思っていたのですが、APIドキュメントには以下のように書かれています。\n\n\n> The URI must use the HTTPS protocol, include a domain name, can’t be an IP address or localhost, and must not contain a fragment identifier (#).\n\napp://などのアプリを開くようなURLは設定できず、httpsのみが許可されていました。\nAndroid App Linksを使用していれば、httpsをアプリで拾って起動できますが、当アプリは未対応のため、一度専用のWebページを開いてそこからカスタムURLスキームを使ってアプリを起動することにしました。\n\n#### 認証完了後\n\nアプリ向けの専用ページからアプリが開かれると、stateとcodeが渡ってくるので、紐づけAPIにローカル保存しているnonceと合わせて紐づけAPIを叩きます。\nその後API側で認証やセキュリティチェックを行い、問題なければアプリに結果を返して、成功ならアプリで紐づけ済みの表示にします。\n\n紐づけ後のログインについては、ほぼ同じ流れで、最後にAPIからID Tokenを返してもらい、それを元にログイン処理を行うため省略します。\n\n# Google\n\nAndroid公式ライブラリであるCredential ManagerとGoogle IDを使うことにしました。\n\n## 画面遷移\n\nGoogleログインのダイアログが開き、アカウントを選択すると、プロフィール画面に戻ります。\n\n1.プロフィール画面でGoogleを押す | 2.アカウントを選択する\n---|---\n|\n3.同意する | 4.連携済みになる\n---|---\n|\n\n## シーケンス\n\nアプリにログインしているユーザーが、SSOを利用するために紐づけを行うシーケンスを説明します。\n大まかな流れとしては、以下になります。\n\n 1. アプリからAPIを使ってnonceを発行\n 2. Credential ManagerでGoogle認証を行う\n 3. アプリからAPIを使って紐づけを依頼\n\n\n\n以下でシーケンス図を使って詳しく説明します。\n\n#### 紐づけボタンを押す\n\nApple SSOと同様に、ログイン済みのユーザーは、プロフィール画面で紐づけを行うことができます。 nonceを利用するところも同様です。\nGoogle SSOでは、Credential Managerを利用することで外部ブラウザを介さなくなるため、CSRFやコードインジェクションのリスクを低減できます。\nそれによって、ID Tokenに含まれるnonceをAPIで検証するだけで良いため、nonceをアプリ側に保存していません。\n\n#### Google認証\n\nライブラリが行ってくれる部分です。 認証に成功すると、ID Tokenが入手できます。\n\n#### 認証完了後\n\nここからはAppleの際とほとんど同じで、API側で検証や紐づけを行い、結果をアプリに返却します。\n\n## 実装方法\n\n公式ドキュメントに、Google Cloud Consoleの設定から、Credential Managerの使い方まで詳しく書いてあります。\n個人的にポイントと思った部分を解説します。\n\n### Google Cloud Consoleの設定\n\nGoogle Cloud Consoleでは、AndroidアプリとWebの`OAuth 2.0 クライアント ID`を作成する必要があります。\nAndroidアプリは、`applicationIdSuffix`などでバリアントによって`applicationId`を変えている場合、テストしたいIDごとにクライアントIDを作成する必要があります。\n\n### 依存関係の追加\n\nGoogle SSOを実装するには、`androidx.credentials:credentials`を含め、以下のライブラリが必要になります。\nバージョンは執筆時点のものです。\n\n * `androidx.credentials:credentials:1.5.0`\n * `androidx.credentials:credentials-play-services-auth:1.5.0`\n * `com.google.android.libraries.identity.googleid:googleid:1.2.0`\n\n\n\n### Googleログインリクエスト\n\n以下がコード例です。\n\n\n suspend fun requestGoogleIdToken(activity: Activity, nonce: Nonce): Result<GoogleIdToken> { val serverClientId = ... val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(serverClientId) .setNonce(nonce.value) .build() val request: GetCredentialRequest = GetCredentialRequest.Builder() .addCredentialOption(signInWithGoogleOption) .build() return try { val resultCredential = credentialManager.getCredential(activity, request).credential if (resultCredential is CustomCredential && resultCredential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(resultCredential.data) Result.Success(GoogleIdToken(googleIdTokenCredential.idToken)) } else { Result.Error(IllegalStateException(\"Credential is not GoogleIdTokenCredential or type mismatch.\")) } } catch (e: GetCredentialCancellationException) { Result.Error(SsoAuthorizationCancellationException()) } catch (t: Throwable) { Result.Error(t) } }\n\n#### GetSignInWithGoogleOption.Builder(serverClientId)\n\nGetSignInWithGoogleOptionのインスタンス化の際に、 `serverClientId`という引数が必要になります。\nこれには、Google Cloud Consoleで作ったAndroidアプリのOAuth 2.0 クライアント ID**ではなく、Webのクライアント IDを指定する** 必要があります。\n\n#### GetCredentialRequest.Builder().addCredentialOption(signInWithGoogleOption)\n\nCredential ManagerのGetCredentialRequestにsignInWithGoogleOptionを入れることで、GoogleSSOが実現できます。\n\n#### GetCredentialCancellationException\n\nユーザーがバックキーなどで処理をキャンセルした場合、このExceptionがスローされるので、エラーとは別に処理する必要があります。\n独自のExceptionに変換しているのは、このアプリがマルチモジュールの設計上、このメソッドを利用するモジュールがCredential Managerに依存しなくなっているからです。\n\n## 動作確認の際の注意点\n\nGoogle Cloud ConsoleにapplicationIdと署名情報を入れる関係で、動作確認の際に認証がうまく行かない場合があります。\n具体的には「Google Cloud Consoleの署名に何を入れるか」と「アプリをどの環境で確認するのか」の組み合わせに依ります。\n\n動作確認には「ローカルビルド」「DeployGate」「Firebase App Distribution」「Google Play」などがあります。\nFirebase App DistributionとGoogle Playの場合は署名が変化する場合があるので、Google Cloud Consoleにどの署名を登録するかによって、確認方法が限られてきます。\n\n例えば、ビルドバリアントとして、debug/rc/releaseの3種類が存在する場合について考えます。\n以下のように設定されています。\n\nビルドバリアント | Google Cloud Consoleに登録する署名\n---|---\ndebug | debug署名\nrc | rc署名\nrelease | Google Play署名\n\nこの設定では、debug/rcはローカルやDeployGateで確認できますが、releaseはGoogle Playから配信しないと確認できません。\nreleaseは実際にユーザーに提供するバリアントなので、Google Play署名にする必要があります。\nGoogle Play署名は、`Google PlayConsoleのテストとリリース > アプリの完全性 > アプリの署名` から確認できます。\n\nまた、Firebase App Distributionはどれとも異なる署名が付与されるため、SSOの動作確認をする際には適さないと判断しました。\n\nGoogle Play署名は、Google側で用意されたものではなく自分でアップロードしたものを使っている場合は、ローカルでも同じ署名にできるので動作確認できることになります。\n\n# Microsoft\n\nMicrosoftが提供しているライブラリを利用することにしました。\nMicrosoft Authentication Library(MSAL)というものです。\n\n## 画面遷移\n\nブラウザでMicrosoftログインを開き、ログインが完了するとアプリが立ち上がり、プロフィール画面が開かれます。\n\n1.プロフィール画面でMicrosoftを押す | 2.Microsoftアカウントでログインする(必要に応じて同意画面が出る) | 3.連携済みになる\n---|---|---\n| |\n\n## シーケンス\n\nアプリにログインしているユーザーが、SSOを利用するために紐づけを行うシーケンスを説明します。\n大まかな流れとしては、以下になります。\n\n 1. アプリからAPIを使ってnonceを発行\n 2. MSALでMicrosoft認証を行う\n 3. アプリからAPIを使って紐づけを依頼\n\n\n\n以下でシーケンス図を使って詳しく説明します。\n\n#### 紐づけボタンを押す\n\nnonceの発行については、Apple/Googleと同じ流れになります。\n\n#### Microsoft認証\n\nここからがMSALの処理です。 ライブラリで外部ブラウザを開き、戻って来るまでをケアしてくれます。 ライブラリを使うと、メソッドを呼ぶことでMicrosoftのID Tokenを返してくれます。\n\n#### 認証完了後\n\nここからはApple/Googleの際とほとんど同じで、API側で検証や紐づけを行い、結果をアプリに返却します。\n\n## 実装方法\n\n公式ページのチュートリアルが参考になります。\n利用するライブラリはmicrosoft-authentication-library-for-androidです。\n本記事ではバージョン `8.2.1` を使っています。\n更新頻度は低いですが、サンプルアプリのリポジトリも存在します。\nライブラリの説明が書かれたページも参考にしました。\n\nチュートリアルの「構成を追加する」にありますが、AndroidManifestの記述とjsonの配置が必要になります。\n\njsonの例\n\n\n { \"client_id\": \"00001111-aaaa-bbbb-3333-cccc4444\", \"authorization_user_agent\": \"BROWSER\", \"redirect_uri\": \"msauth://com.azuresamples.msalandroidapp/1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D\", \"broker_redirect_uri_registered\": false, \"account_mode\": \"MULTI\", \"authorities\": [ { \"type\": \"AAD\", \"authority_url\": \"https://login.microsoftonline.com/common\" } ] }\n\n何を設定するかは、Android Microsoft Authentication Library configuration fileに詳しい記載があります。\n\n### 署名について\n\n特に注意が必要なのが `redirect_uri` で、 `msauth://パッケージ名/base64エンコードされた署名` となります。\n公式のよくある質問にも解説があります。\n署名はローカルの場合と、Google Play署名の場合の2パターンあったので、それぞれ取得した方法を紹介します。\n\n#### ローカル\n\nkeystoreのSHA-1署名を取得します。\n\n\n keytool -list -v -alias alias -keystore sample.keystore\n\n証明書のフィンガープリントとして、SHA-1の署名が出力されます。\n署名の例(公式ドキュメントのもの):`D7:02:2A:5D:2A:81:8F:BC:3E:87:5D:59:89:FB:27:AB:08:32:2A:B6`\n\n署名から:を消し、それをバイナリにしてbase64エンコードします。\n\n\n echo \"D7:02:2A:5D:2A:81:8F:BC:3E:87:5D:59:89:FB:27:AB:08:32:2A:B6\" | tr -d ':'| xxd -r -p | base64\n\nすると、以下の文字列が得られます。\n`1wIqXSqBj7w+h11ZifsnqwgyKrY=`\n\nこれをURLエンコードします。\n\n\n python3 -c 'import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))' \"1wIqXSqBj7w+h11ZifsnqwgyKrY=\"\n\n`1wIqXSqBj7w%2Bh11ZifsnqwgyKrY%3D`\nこれをredirect_uriに設定します。\n\n#### Google Play\n\nGoogle Play署名は、Google PlayConsoleの `テストとリリース > アプリの完全性 > アプリの署名` から確認できます。\nここでSHA-1証明書のフィンガープリントをコピーして、ローカルと同じ手順でbase64文字列を生成できます。\nまたは、Google PlayConsoleで「証明書をダウンロード」を押してDLできる証明書ファイル`deployment_cert.der`を使うこともできます。\nその場合、以下のコマンドを使うことで、base64文字列を生成できます。\n\n\n openssl sha1 -binary deployment_cert.der | base64\n\n### authorization_user_agent\n\n`DEFAULT`,`WEBVIEW`,`BROWSER`の3種類のうちから選択します。(詳しい説明)\nブローカー認証(Microsoft Authenticator / Intune Company Portal など)を使わない場合、`BROWSER`を選択します。(こちらのドキュメント)に説明があります。 当アプリでは`BROWSER`を選択しました。\n\n### broker_redirect_uri_registered\n\nブローカー認証を行う場合はtrueにします。当アプリでは、行わないためfalseです。\n\n### account_mode\n\n`SINGLE`と`MULTI`があります。\n\nパラメーター | 説明\n---|---\nSINGLE | 同時に扱えるアカウントが常に一つ。社内業務(LoB)アプリ/共有デバイス(キオスク・現場端末)などに向く。\nMULTI | 複数アカウントが存在でき、切り替えられる。個人/組織アカウントを切り替えるユースケースに向く。\n\n今回はMULTIを選択しました。\n1つに制限する必要がなく、すでにブラウザでMicrosoftアカウントにログイン済みの場合でも、別のアカウントと紐づけることを可能とするためです。\n\n### AndroidManifest\n\n次にAndroidManifestの例です。\n`authorization_user_agent`で`BROWSER`を選択した場合は、AndroidManifestに定義が必要です。\n\n\n <activity android:name=\"com.microsoft.identity.client.BrowserTabActivity\" android:exported=\"true\"> <intent-filter> <action android:name=\"android.intent.action.VIEW\" /> <category android:name=\"android.intent.category.DEFAULT\" /> <category android:name=\"android.intent.category.BROWSABLE\" /> <data android:scheme=\"msauth\" android:host=\"com.azuresamples.msalandroidapp\" android:path=\"/1wIqXSqBj7w+h11ZifsnqwgyKrY=\" /> </intent-filter> </activity>\n\n`BrowserTabActivity`は、ブラウザからアプリを起動するためのもので、ライブラリ内に定義されています。\nintent-filterのdataに、アプリ固有の設定をしていきます。\n\nschemeは`msauth`固定です。\n`host`には、アプリケーションIDを設定します。\napplicationIdSuffixなどでバリアントによってapplicationIdを変えている場合は、バリアントごとのstrings.xmlにapplicationIdを定義しておくとAndroidManifestの定義が1つで良くなり、メンテナンス性が上がります。\n`path`には/とbase64エンコードされた署名を定義します。\njsonの定義と異なり、こちらはURLエンコードしないので注意が必要です。\nこちらも、バリアントがあればそれごとにstrings.xmlに定義すると良いと思います。\n\n### コード例\n\nここまでで設定が完了したので、ライブラリを使うコード例を示します。(MultipleAccountの例です)\n大枠の使い方としては、以下になります。\n\n 1. IMultipleAccountPublicClientApplicationの作成\n 2. 作成したApplicationのacquireTokenを呼ぶ\n 3. acquireTokenの引数にcallbackを指定でき、そこに結果が返ってくる\n\n\n\nコード例では、callbackをsuspend関数に変換し、MicrosoftIdToken(value class)を返すクラスを作成しています。\n\n\n internal class MicrosoftAuthenticationImpl @Inject constructor( @ApplicationContext private val context: Context, @Dispatcher(DispatcherType.IO) private val ioDispatcher: CoroutineDispatcher ): MicrosoftAuthentication { override suspend fun requestMicrosoftIdToken(activity: Activity, nonce: Nonce): Result<MicrosoftIdToken> = withContext(ioDispatcher) { when (val result = createMultipleAccountPublicClientApplication()) { is Result.Success -> { suspendCancellableCoroutine<Result<MicrosoftIdToken>> { val parameters: AcquireTokenParameters = AcquireTokenParameters.Builder() .startAuthorizationFromActivity(activity) .withScopes(listOf(\"email\")) .withPrompt(Prompt.SELECT_ACCOUNT) .withAuthorizationQueryStringParameters(listOf(AbstractMap.SimpleEntry(\"nonce\", nonce.value))) .withCallback(createAuthenticationCallback(it)) .build() val clientApplication = result.value clientApplication.acquireToken(parameters) } } is Result.Error -> { Result.Error(result.exception) } } } private suspend fun createMultipleAccountPublicClientApplication(): Result<IMultipleAccountPublicClientApplication> { return suspendCancellableCoroutine { PublicClientApplication.createMultipleAccountPublicClientApplication( context, R.raw.credential_microsoft_auth_config, object : IMultipleAccountApplicationCreatedListener { override fun onCreated(application: IMultipleAccountPublicClientApplication) { it.resume(Result.Success(application)) } override fun onError(exception: MsalException) { it.resume(Result.Error(exception)) } }) } } private fun createAuthenticationCallback(continuation: Continuation<Result<MicrosoftIdToken>>): AuthenticationCallback { return object: AuthenticationCallback { override fun onSuccess(authenticationResult: IAuthenticationResult?) { val idToken = authenticationResult?.account?.idToken if (idToken != null) { continuation.resume(Result.Success(MicrosoftIdToken(idToken))) } else { val exception = IllegalStateException(\"ID Token is null.\") continuation.resume(Result.Error(exception)) } } override fun onCancel() { continuation.resume(Result.Error(SsoAuthorizationCancellationException())) } override fun onError(exception: MsalException) { if (exception.errorCode == MsalServiceException.ACCESS_DENIED) { continuation.resume(Result.Error(SsoAuthorizationCancellationException())) } else { continuation.resume(Result.Error(exception)) } } } } }\n\n#### createMultipleAccountPublicClientApplication\n\n`createMultipleAccountPublicClientApplication` では、IMultipleAccountPublicClientApplicationを作成します。\n`R.raw.credential_microsoft_auth_config` は、先に説明したjson形式の設定ファイルです。\n\n`createMultipleAccountPublicClientApplication`に成功すると、`IMultipleAccountPublicClientApplication`が取得でき、ID Token取得のための `acquireToken`を呼ぶことができます。\n\n#### AcquireTokenParameters\n\n`acquireToken`に必要な `AcquireTokenParameters`の引数はScopes, Activity, Callbackが必須となっています。(ドキュメント)\n\n`withScopes`では、emailを指定しており、これは受け入れ可能なドメインを学校で設定し、それを検証するためです。\nscopeについてはResources and scopesが参考になります。\n\n`withPrompt`は、SELECT_ACCOUNTを指定しており、認証済みのアカウントがなければログイン画面、あればアカウントを選択する画面を表示するようにしています。\nwithPromptの選択肢と説明はPrompt Enumが参考になります。\n\n`withAuthorizationQueryStringParameters`には、nonceを入れています。 先に説明したnonceですが、Apple/Google/Microsoftすべての認証で利用しています。\nID Tokenの中に入っているnonceを検証するために付与しています。\n\n`withCallback`で指定したCallbackに結果が返るようになっています。\nこれをsuspend関数にするため、suspendCancellableCoroutineを使っています。\n\n#### createAuthenticationCallback\n\n認証に成功した場合、authenticationResult > account > idTokenにID Tokenが入っています。\n\n## 動作確認の際の注意点\n\nMicrosoftSSOも、GoogleSSOと同様に署名情報を利用するため、動作確認の際にはGoogle Playからの配信など適切な方法を選ぶ必要があります。\n\n# おわりに\n\n今回は、Apple/Google/MicrosoftのSSOについて解説しました。\nライブラリや環境設定など、注意するポイントがあり、調べながら試しながら実装していきました。\n認証周りの導入はそう何度もあることではないので、良い経験ができたと思っています。",
"title": "AndroidアプリでApple・Google・Microsoftのシングルサインオンを実装した話",
"updatedAt": "2026-03-23T00:00:01.000Z"
}