Android 用の ADAL から MSAL への移行ガイド

この記事では、Azure Active Directory認証ライブラリ (ADAL) を使用してMicrosoft Authentication Library (MSAL) を使用するアプリを移行するために必要な変更について説明します。

相違点の強調表示

ADAL は、Azure AD v1.0 エンドポイントで動作します。 Microsoft Authentication Library (MSAL) は、以前は Azure AD v2.0 エンドポイントと呼ばれるMicrosoft ID プラットフォームで動作します。 Microsoft ID プラットフォームは、Azure AD v1.0 とは異なります。

サポート:

  • 組織 ID (Microsoft Entra ID)

  • Outlook.com、Xbox Live などの組織以外の ID

  • (Azure AD B2C のみ) Google、Facebook、X、Amazon とのフェデレーション ログイン

  • 標準は次と互換性があります。

    • OAuth v2.0
    • OpenID Connect (OIDC)

MSAL パブリック API では、次のような重要な変更が導入されています。

  • トークンにアクセスするための新しいモデル:
    • ADAL は、サーバーを表す AuthenticationContextを介してトークンへのアクセスを提供します。 MSAL は、クライアントを表す PublicClientApplicationを介してトークンへのアクセスを提供します。 クライアント開発者は、対話する必要があるすべての機関に対して新しい PublicClientApplication インスタンスを作成する必要はありません。 必要な PublicClientApplication 構成は 1 つだけです。
    • リソース識別子に加えて、スコープを使用してアクセス トークンを要求するためのサポート。
    • 段階的な同意をサポート。 開発者は、アプリの登録時に含まれていない機能を含め、ユーザーがアプリの機能にアクセスするにつれてスコープを要求できます。
    • 権限は実行時に検証されなくなりました。 代わりに、開発者は開発中に "既知の機関" の一覧を宣言します。
  • トークン API の変更:
    • ADAL では、 AcquireToken() は最初にサイレント要求を行います。 それができない場合は、対話型要求を行います。 この動作により、一部の開発者は AcquireTokenのみに依存し、その結果、ユーザーは予期せず資格情報の入力を求められる場合がありました。 MSAL では、ユーザーが UI プロンプトを受け取るタイミングについて開発者が意図的に行う必要があります。
      • AcquireTokenSilent は常に、成功または失敗するサイレント要求になります。
      • AcquireToken は常に、UI 経由でユーザーにプロンプトを表示する要求になります。
  • MSAL では、既定のブラウザーまたは埋め込み Web ビューからのサインインがサポートされています。
    • 既定では、デバイスの既定のブラウザーが使用されます。 これにより、MSAL は、サインインしている 1 つ以上のアカウントに既に存在する可能性がある認証状態 (Cookie) を使用できます。 認証状態が存在しない場合、MSAL による承認時に認証を行うと、同じブラウザーで使用される他の Web アプリケーションの利点のために認証状態 (Cookie) が作成されます。
  • 新しい例外モデル:
    • 例外により、発生したエラーの種類と、開発者がそれを解決するために何を行う必要があるかがより明確に定義されます。
  • MSAL では、 AcquireToken 呼び出しと AcquireTokenSilent 呼び出しのパラメーター オブジェクトがサポートされています。
  • MSAL では、次の宣言型構成がサポートされています。
    • クライアント ID、リダイレクト URI。
    • 埋め込みブラウザーと既定のブラウザー
    • 当局
    • 読み取りと接続タイムアウトなどの HTTP 設定

アプリの登録と MSAL への移行

MSAL を使用するために既存のアプリ登録を変更する必要はありません。 増分/プログレッシブ同意を利用する場合は、登録を確認して、増分的に要求する特定のスコープを特定することが必要になる場合があります。 スコープと増分同意の詳細については、以下を参照してください。

ポータルでアプリを登録すると、[ API のアクセス許可 ] タブが表示されます。これにより、アプリが現在アクセスを要求するように構成されている API とアクセス許可 (スコープ) の一覧が表示されます。 また、各 API アクセス許可に関連付けられているスコープ名の一覧も表示されます。

ADAL と Azure AD v1.0 エンドポイントでは、ユーザーが所有するリソースに対するユーザーの同意が最初の使用時に付与されました。 MSAL とMicrosoft ID プラットフォームを使用すると、同意を段階的に要求できます。 増分同意は、ユーザーが高い特権を考慮する可能性があるアクセス許可に役立ちます。また、アクセス許可が必要な理由について明確な説明が提供されていない場合は疑問を持つ場合があります。 ADAL では、これらのアクセス許可により、ユーザーがアプリへのサインインを中止した可能性があります。

Tip

増分同意を使用して、アプリにアクセス許可が必要な理由に関する追加のコンテキストをユーザーに提供します。

組織の管理者は、組織のすべてのメンバーに代わってアプリケーションに必要なアクセス許可に同意できます。 一部の組織では、管理者のみがアプリケーションに同意できます。 管理者の同意を得るには、アプリケーションによって使用されるすべての API アクセス許可とスコープをアプリの登録に含める必要があります。

Tip

アプリの登録に含まれていないものに対して MSAL を使用してスコープを要求できますが、ユーザーがアクセス許可を付与できるすべてのリソースとスコープを含むようにアプリの登録を更新することをお勧めします。

リソース ID からスコープへの移行

初回使用時に認証を行い、必要なすべての権限の承認を要求します

現在 ADAL を使用していて、増分同意を使用する必要がない場合、MSAL の使用を開始する最も簡単な方法は、新しいacquireToken オブジェクトを使用してAcquireTokenParameter要求を行い、リソース ID 値を設定することです。

Caution

スコープとリソース ID の両方を設定することはできません。両方を設定しようとすると、 IllegalArgumentExceptionが発生します。

これにより、使用されているのと同じ v1 動作が発生します。 アプリの登録で要求されたすべてのアクセス許可は、最初の操作中にユーザーから要求されます。

必要に応じてのみ認証し、アクセス許可を要求する

増分同意を利用するには、アプリの登録からアプリが使用するアクセス許可 (スコープ) の一覧を作成し、次に基づいて 2 つのリストに整理します。

  • サインイン時にユーザーがアプリと最初にやり取りするときに要求するスコープ。
  • ユーザーに説明する必要があるアプリの重要な機能に関連付けられているアクセス許可。

スコープを整理したら、トークンを要求するリソース (API) ごとに各リストを整理します。 および、同時にユーザーに承認してもらいたいその他のスコープ。

MSAL への要求を行うために使用される parameters オブジェクトは、次をサポートします。

  • Scope: アクセス トークンの承認と受信を要求するスコープの一覧。
  • ExtraScopesToConsent: 別のリソースのアクセス トークンを要求している間に承認を要求するスコープの追加リスト。 このスコープの一覧を使用すると、ユーザー承認を要求する必要がある回数を最小限に抑えることができます。 つまり、ユーザーの承認または同意のプロンプトが少なくなります。

AuthenticationContext から PublicClientApplications への移行

PublicClientApplication の構築

MSAL を使用する場合は、 PublicClientApplicationをインスタンス化します。 このオブジェクトはアプリ ID をモデル化し、1 つ以上の機関に要求を行うために使用されます。 このオブジェクトを使用すると、クライアント ID、リダイレクト URI、既定の機関、デバイス ブラウザーと埋め込み Web ビュー、ログ レベルなどを使用するかどうかを構成します。

このオブジェクトは、ファイルとして指定するか、APK 内のリソースとして格納する JSON を使用して宣言によって構成できます。

このオブジェクトはシングルトンではありませんが、内部的には対話型要求とサイレント要求の両方に共有 Executors を使用します。

BtoB

ADAL では、アクセス トークンを要求するすべての組織に、 AuthenticationContextの個別のインスタンスが必要です。 MSAL では、これは要件ではなくなりました。 サイレントまたは対話型の要求の一部としてトークンを要求する機関を指定できます。

機関検証から既知の機関への移行

MSAL には、機関の検証を有効または無効にするフラグがありません。 機関の検証は、ADAL および MSAL の初期リリースの機能であり、悪意のある可能性のある機関からコードがトークンを要求するのを防ぎます。 MSAL は、Microsoft に認識されている認証機関の一覧を取得し、その一覧を構成設定で指定した認証機関とマージします。

Tip

Azure Business to Consumer (B2C) ユーザーの場合は、機関の検証を無効にする必要がなくなりました。 代わりに、サポートされている各Azure AD B2C ポリシーを MSAL 構成の機関として含めます。 2025 年 5 月 1 日より、Azure AD B2C は新規のお客様による購入ができなくなります。 詳細については、FAQ の 「Azure AD B2C を引き続き購入できますか?」を 参照してください。

Microsoft に認識されておらず、かつ構成に含まれていない認証機関を使用しようとした場合、UnknownAuthorityException が表示されます。

Logging

次のように、構成の一部としてログ記録を宣言的に構成できるようになりました。

"logging": {
  "pii_enabled": false,
  "log_level": "WARNING",
  "logcat_enabled": true
}

UserInfo からアカウントへの移行

ADAL では、 AuthenticationResult は、認証されたアカウントに関する情報を取得するために使用される UserInfo オブジェクトを提供します。 人間またはソフトウェア エージェントを意味する "user" という用語は、複数のアカウントを持つ 1 人のユーザー (人間またはソフトウェア エージェント) を一部のアプリがサポートしていることを伝えにくくする方法で適用されました。

銀行口座について考えてみましょう。 複数の金融機関で複数のアカウントを持っている可能性があります。 アカウントを開くと、お客様 (ユーザー) には、残高へのアクセス、支払いの請求などに使用される、ATM カードや PIN などの資格情報がアカウントごとに発行されます。 これらの資格情報は、発行した金融機関でのみ使用できます。

金融機関のアカウントと同様に、Microsoft ID プラットフォームのアカウントには資格情報を使用してアクセスします。 これらの資格情報は、Microsoftに登録されているか、Microsoftによって発行されます。 または、Microsoft が組織に代わって行う。

Microsoft ID プラットフォームが金融機関と異なる場合、この例では、Microsoft ID プラットフォームは、ユーザーが 1 つのアカウントとそれに関連付けられた資格情報を使用して、複数の個人と組織に属するリソースにアクセスできるようにするフレームワークを提供することです。 これは、ある銀行が発行したカードを、さらに別の金融機関で使用できるようなものです。 これは、問題のすべての組織がMicrosoft ID プラットフォームを使用しているために機能します。これにより、複数の組織で 1 つのアカウントを使用できます。 次に例を示します。

Sam は Contoso.com で機能しますが、Fabrikam.com に属Azure仮想マシンを管理します。 Sam が Fabrikam の仮想マシンを管理するには、それらにアクセスする権限が必要です。 このアクセス権を付与するには、Sam のアカウントを Fabrikam.com に追加し、仮想マシンを操作できるロールを自分のアカウントに付与します。 これは、Azure ポータルで行います。

Sam の Contoso.com アカウントを Fabrikam.com のメンバーに追加すると、Fabrikam.com の Microsoft Entra ID に Sam の新しいレコードが作成されます。 Microsoft Entra IDでの Sam のレコードは、ユーザー オブジェクトと呼ばれます。 この場合、そのユーザー オブジェクトは Contoso.com の Sam のユーザー オブジェクトを指します。 Sam の Fabrikam ユーザー オブジェクトは Sam のローカル表現であり、sam に関連付けられているアカウントに関する情報を Fabrikam.com のコンテキストに格納するために使用されます。 Contoso.com では、Sam のタイトルはシニア DevOps コンサルタントです。 Fabrikam では、Sam のタイトルは Contractor-Virtual Machines です。 Contoso.com では、Sam は仮想マシンを管理する責任も承認もされません。 Fabrikam.com では、それが彼の唯一の仕事の機能です。 ただし、Sam は追跡する資格情報のセットを 1 つだけ持っています。これは、Contoso.com によって発行された資格情報です。

acquireToken呼び出しが成功すると、後のIAccount要求で使用できるacquireTokenSilent オブジェクトへの参照が表示されます。

IMultiTenantAccount

アカウントが表されている各テナントのアカウントに関する要求にアクセスするアプリがある場合は、 IAccount オブジェクトを IMultiTenantAccountにキャストできます。 このインターフェイスは、テナント ID でキー指定された ITenantProfilesのマップを提供します。これにより、現在のアカウントを基準にして、トークンを要求した各テナントのアカウントに属する要求にアクセスできます。

IAccountおよびIMultiTenantAccountのルートにある要求には、常にホーム テナントからの要求が含まれます。 ホーム テナント内でトークンの要求をまだ行っていない場合、このコレクションは空になります。

その他の変更

新しい AuthenticationCallback を使用する

// Existing ADAL Interface
public interface AuthenticationCallback<T> {

    /**
     * This will have the token info.
     *
     * @param result returns <T>
     */
    void onSuccess(T result);

    /**
     * Sends error information. This can be user related error or server error.
     * Cancellation error is AuthenticationCancelError.
     *
     * @param exc return {@link Exception}
     */
    void onError(Exception exc);
}
// New Interface for Interactive AcquireToken
public interface AuthenticationCallback {

    /**
     * Authentication finishes successfully.
     *
     * @param authenticationResult {@link IAuthenticationResult} that contains the success response.
     */
    void onSuccess(final IAuthenticationResult authenticationResult);

    /**
     * Error occurs during the authentication.
     *
     * @param exception The {@link MsalException} contains the error code, error message and cause if applicable. The exception
     *                  returned in the callback could be {@link MsalClientException}, {@link MsalServiceException}
     */
    void onError(final MsalException exception);

    /**
     * Will be called if user cancels the flow.
     */
    void onCancel();
}

// New Interface for Silent AcquireToken
public interface SilentAuthenticationCallback {

    /**
     * Authentication finishes successfully.
     *
     * @param authenticationResult {@link IAuthenticationResult} that contains the success response.
     */
    void onSuccess(final IAuthenticationResult authenticationResult);

    /**
     * Error occurs during the authentication.
     *
     * @param exception The {@link MsalException} contains the error code, error message and cause if applicable. The exception
     *                  returned in the callback could be {@link MsalClientException}, {@link MsalServiceException} or
     *                  {@link MsalUiRequiredException}.
     */
    void onError(final MsalException exception);
}

新しい例外に移行する

ADAL には、 AuthenticationExceptionという 1 種類の例外があります。これには、 ADALError 列挙値を取得するためのメソッドが含まれています。 MSAL には例外の階層があり、それぞれに固有の関連する特定のエラー コードのセットがあります。

例外 説明
MsalArgumentException 1 つ以上の入力引数が無効な場合にスローされます。
MsalClientException エラーがクライアント側の場合にスローされます。
MsalDeclinedScopeException 1 つ以上の要求したスコープがサーバーに拒否された場合にスローされます。
MsalException MSAL によってスローされた既定のチェック例外。
MsalIntuneAppProtectionPolicyRequiredException リソースで MAMCA 保護ポリシーが有効になっている場合にスローされます。
MsalServiceException エラーがサーバー側の場合にスローされます。
MsalUiRequiredException トークンをサイレントで更新できない場合にスローされます。
MsalUserCancelException ユーザーが認証フローをキャンセルした場合にスローされます。

ADALError から MsalException への変換

ADAL でこれらのエラーをキャッチしている場合... ...次の MSAL 例外をキャッチします。
同等の ADALError がない MsalArgumentException
  • ADALError.ANDROIDKEYSTORE_FAILED
  • ADALError.AUTH_FAILED_USER_MISMATCH
  • ADALError.DECRYPTION_FAILED
  • ADALError.DEVELOPER_AUTHORITY_CAN_NOT_BE_VALIDED
  • ADALError.DEVELOPER_AUTHORITY_IS_NOT_VALID_INSTANCE
  • ADALError.DEVELOPER_AUTHORITY_IS_NOT_VALID_URL
  • ADALError.DEVICE_CONNECTION_IS_NOT_AVAILABLE
  • ADALError.DEVICE_NO_SUCH_ALGORITHM
  • ADALError.ENCODING_IS_NOT_SUPPORTED
  • ADALError.ENCRYPTION_ERROR
  • ADALError.IO_EXCEPTION
  • ADALError.JSON_PARSE_ERROR
  • ADALError.NO_NETWORK_CONNECTION_POWER_OPTIMIZATION
  • ADALError.SOCKET_TIMEOUT_EXCEPTION
MsalClientException
同等の ADALError がない MsalDeclinedScopeException
  • ADALError.APP_PACKAGE_NAME_NOT_FOUND
  • ADALError.BROKER_APP_VERIFICATION_FAILED
  • ADALError.PACKAGE_NAME_NOT_FOUND
MsalException
同等の ADALError がない MsalIntuneAppProtectionPolicyRequiredException
  • ADALError.SERVER_ERROR
  • ADALError.SERVER_INVALID_REQUEST
MsalServiceException
  • ADALError.AUTH_REFRESH_FAILED_PROMPT_NOT_ALLOWED
MsalUiRequiredException
同等の ADALError がない MsalUserCancelException

ADAL のログ記録から MSAL のログ記録へ

// Legacy Interface
    StringBuilder logs = new StringBuilder();
    Logger.getInstance().setExternalLogger(new ILogger() {
            @Override
            public void Log(String tag, String message, String additionalMessage, LogLevel logLevel, ADALError errorCode) {
                logs.append(message).append('\n');
            }
        });
// New interface
  StringBuilder logs = new StringBuilder();
  Logger.getInstance().setExternalLogger(new ILoggerCallback() {
      @Override
      public void log(String tag, Logger.LogLevel logLevel, String message, boolean containsPII) {
          logs.append(message).append('\n');
      }
  });

// New Log Levels:
public enum LogLevel
{
    /**
     * Error level logging.
     */
    ERROR,
    /**
     * Warning level logging.
     */
    WARNING,
    /**
     * Info level logging.
     */
    INFO,
    /**
     * Verbose level logging.
     */
    VERBOSE
}