認証の処理
認証の種類
拡張機能では、1 つまたは複数の種類の認証をサポートできます。 認証の種類ごとに、資格情報の種類が異なります。 Power Query のエンド ユーザーに表示される認証 UI は、拡張機能がサポートしている資格情報の種類によって決まります。
サポートされている認証の種類の一覧は、拡張機能の [データ ソースの種類] の定義の一部として定義されます。 各認証値は、特定のフィールドを含んだレコードです。 次の表は、各種類の必須フィールドを示したものです。 特に指定しない限り、すべてのフィールドが必須となります。
| 認証の種類 | フィールド | 説明 |
|---|---|---|
| 暗黙 | 暗黙的 (匿名) 認証の種類にはフィールドはありません。 | |
| OAuth | StartLogin | OAuth フローを開始するための URL と状態情報を提供する関数。 後述の「OAuth フローの実装」セクションを参照してください。 |
| FinishLogin | OAuth フローに関連する access_token とその他のプロパティを抽出する関数。 | |
| 更新 | (省略可能) 更新トークンから新しいアクセス トークンを取得する関数。 | |
| Logout | (省略可能) ユーザーの現在のアクセス トークンを無効にする関数。 | |
| Label | (省略可能) この AuthenticationKind の既定のラベルをオーバーライドできるテキスト値。 | |
| Aad | AuthorizationUri | Azure AD 認証エンドポイントを返す text 値または関数 (例: "https://login.microsoftonline.com/common/oauth2/authorize")。後述の「Azure Active Directory 認証」セクションを参照してください。 |
| リソース | サービスの Azure AD リソース値を返す text 値または関数。 |
|
| UsernamePassword | UsernameLabel | (省略可能) 資格情報 UI の [ユーザー名] テキスト ボックスの既定のラベルを置き換えるテキスト値。 |
| PasswordLabel | (省略可能) 資格情報 UI の [パスワード] テキスト ボックスの既定のラベルを置き換えるテキスト値。 | |
| Label | (省略可能) この AuthenticationKind の既定のラベルをオーバーライドできるテキスト値。 | |
| Windows | UsernameLabel | (省略可能) 資格情報 UI の [ユーザー名] テキスト ボックスの既定のラベルを置き換えるテキスト値。 |
| PasswordLabel | (省略可能) 資格情報 UI の [パスワード] テキスト ボックスの既定のラベルを置き換えるテキスト値。 | |
| Label | (省略可能) この AuthenticationKind の既定のラベルをオーバーライドできるテキスト値。 | |
| キー | KeyLabel | (省略可能) 資格情報 UI の [API キー] テキスト ボックスの既定のラベルを置き換えるテキスト値。 |
| Label | (省略可能) この AuthenticationKind の既定のラベルをオーバーライドできるテキスト値。 |
次のサンプルは、OAuth、Key、Windows、Basic (ユーザー名とパスワード)、および匿名の資格情報をサポートしたコネクタの認証レコードを示したものです。
例:
Authentication = [
OAuth = [
StartLogin = StartLogin,
FinishLogin = FinishLogin,
Refresh = Refresh,
Logout = Logout
],
Key = [],
UsernamePassword = [],
Windows = [],
Implicit = []
]
現在の資格情報へのアクセス
現在の資格情報は、Extension.CurrentCredential() 関数を使用して取得できます。
機能拡張に対して有効になっている M データ ソース関数は、拡張機能の資格情報スコープを自動的に継承します。 ほとんどの場合、現在の資格情報に明示的にアクセスする必要はありませんが、次のような例外があります。
- カスタムヘッダーまたはクエリ文字列パラメーターで資格情報を渡す (API キーの認証の種類を使用する場合など)
- ODBC または ADO.NET 拡張機能の接続文字列プロパティを設定する
- OAuth トークンのカスタム プロパティをチェックする
- OAuth v1 フローの一部として資格情報を使用する
Extension.CurrentCredential() 関数はレコード オブジェクトを返します。 これに含まれるフィールドは、認証の種類によって異なります。 詳細については、次の表を参照してください。
| フィールド | 説明 | 使用者 |
|---|---|---|
| AuthenticationKind | この資格情報 (UsernamePassword、OAuth など) に割り当てられている認証の種類の名前が含まれます。 | すべて |
| ユーザー名 | ユーザー名の値 | UsernamePassword、Windows |
| Password | パスワードの値。 通常は UsernamePassword と共に使用されますが、Key に対しても設定されます。 | Key、UsernamePassword、Windows |
| access_token | OAuth アクセス トークンの値。 | OAuth |
| プロパティ | 当該の資格情報の他のカスタム プロパティを含んだレコード。 通常、認証フローで access_token と共に返される追加のプロパティ (refresh_token など) を格納するために、OAuth と共に使用されます。 | OAuth |
| キー | API キーの値。 このキー値は、[パスワード] フィールドでも使用できます。 既定では、マッシュアップ エンジンはこの値が基本認証パスワード (ユーザー名なし) であるかのように、これを Authorization ヘッダーに挿入します。 そのように動作させたくない場合は、オプションレコードで ManualCredentials = true オプションを指定する必要があります。 | キー |
| EncryptConnection | データソースへの暗号化された接続を必須とするかどうかを決定する論理値。 この値はすべての認証の種類で使用できますが、[データ ソース] の定義で EncryptConnection が指定されている場合にのみ設定されます。 | すべて |
次のコード サンプルでは、API キーの現在の資格情報にアクセスし、それを使ってカスタム ヘッダー (x-APIKey) を設定しています。
例:
MyConnector.Raw = (_url as text) as binary =>
let
apiKey = Extension.CurrentCredential()[Key],
headers = [
#"x-APIKey" = apiKey,
Accept = "application/vnd.api+json",
#"Content-Type" = "application/json"
],
request = Web.Contents(_url, [ Headers = headers, ManualCredentials = true ])
in
request
OAuth フローの実装
認証の種類として OAuth を使用すると、拡張機能でサービスのカスタム ロジックを実装できます。
これを行うには、拡張機能で、StartLogin (OAuth フローを開始するための承認 URI を返す) の関数と、FinishLogin (アクセス トークンの承認コードを交換する) の関数を提供します。
拡張機能では、必要に応じて、Refresh (更新トークンを新しいアクセス トークンと交換する) と Logout (現在の更新トークンとアクセス トークンを期限切れにする) の関数も実装できます。
注意
Power Query の拡張機能は、クライアント コンピューターで実行されているアプリケーション内で評価されます。 データ コネクタでは、OAuth フロー内で機密シークレットを使用しないようにしてください。ユーザーが拡張機能やネットワーク トラフィックを調べて、シークレットを探り出す可能性があります。 共有シークレットに依存しないフローを提供する方法について詳しくは、OAuth パブリック クライアントによるコード交換のための証明キー (PKCE とも呼ばれる) に関する RFC を参照してください。 このフローの実装例は、Microsoft の GitHub サイトで確認できます。
OAuth 関数のシグネチャには、2 つのセットがあります。最小限の数のパラメーターを含んだ元のシグネチャと、追加のパラメーターを受け取る高度なシグネチャです。 ほとんどの OAuth フローは、元のシグネチャを使って実装できます。 実装内でシグネチャの種類を組み合わせて使用することもできます。 関数呼び出しは、パラメーターの数 (および種類) に対応したものとなります。 パラメーター名は考慮に入れられません。
詳細については、Github のサンプルを参照してください。
元の OAuth シグネチャ
StartLogin = (dataSourcePath, state, display) => ...;
FinishLogin = (context, callbackUri, state) => ...;
Refresh = (dataSourcePath, refreshToken) => ...;
Logout = (accessToken) => ...;
高度な OAuth シグネチャ
高度なシグネチャに関する注意事項:
- すべてのシグネチャは、
clientApplicationレコードの値を受け取ります (これは将来の使用のために予約されています)。 - すべてのシグネチャは
dataSourcePathを受け入れます (多くサンプルではresourceUrlとも呼ばれます)。 Refresh関数はoldCredentialパラメーターを受け取ります。これは、FinishLogin関数によって返された、以前のrecord(またはRefreshに対する以前の呼び出し) です。
StartLogin = (clientApplication, dataSourcePath, state, display) => ...;
FinishLogin = (clientApplication, dataSourcePath, context, callbackUri, state) => ...;
Refresh = (clientApplication, dataSourcePath, oldCredential) => ...;
Logout = (clientApplication, dataSourcePath, accessToken) => ...;
Azure Active Directory 認証
Aad 認証は、Azure Active Directory のための特殊なバージョンの OAuth です。 組織アカウント認証をサポートした組み込みの Power Query コネクタと同じ Azure AD クライアントが使用されます。
注意
データ ソースに user_impersonation 以外のスコープが必要な場合や、user_impersonation を使用するための互換性がない場合は、認証の種類として OAuth を使用する必要があります。
注意
Azure AD に対して独自の OAuth フローを実装した場合、自分のテナントに対して条件付きアクセスを有効にしているユーザーは、Power BI サービスを使って更新を行う際に問題に遭遇する可能性があります。 これは、ゲートウェイベースの更新には影響を与えませんが、Power BI サービスからの更新をサポートした認定済みコネクタには影響を与えます。 ユーザーは、Power BI サービスを通じて Web ベースの資格情報を構成する際に、パブリック クライアント アプリケーションを使ったコネクタに起因する問題に遭遇する可能性があります。 このフローによって生成されたアクセス トークンは、最終的に、最初の認証に使用されたコンピューター (つまり、会社のネットワーク上でデータ ソースの資格情報を構成するユーザーのコンピューター) とは異なるコンピューター (つまり、会社のネットワーク上ではなく、Azure データ センター内の Power BI サービス) で使用されます。 組み込みの種類である Aad では、Power BI サービスで資格情報を構成する際に別の Azure AD クライアントを使用することで、この問題が回避されます。 このオプションは、OAuth 認証を使用するコネクタでは使用できません。
ほとんどのコネクタでは、AuthorizationUri フィールドと Resource フィールドの値を指定する必要があります。 どちらのフィールドにも、text 値を指定するか、text value を返す 1 つの引数関数を指定できます。
AuthorizationUri = "https://login.microsoftonline.com/common/oauth2/authorize"
AuthorizationUri = (dataSourcePath) => FunctionThatDeterminesAadEndpointFromDataSourcePath(dataSourcePath)
Resource = "77256ee0-fe79-11ea-adc1-0242ac120002" // Azure AD resource value for your service - Guid or URL
Resource = (dataSourcePath) => FunctionThatDeterminesResourceFromDataSourcePath(dataSourcePath)
Uri ベースの識別子を使用するコネクタでは、Resource の値を指定する必要があります。
既定では、この値はコネクタの Uri パラメーターのルート パスと同じになります。
データ ソースの Azure AD リソースがドメイン値と異なる (たとえば、GUID を使用している) 場合は、Resource 値を指定する必要があります。
Aad 認証のサンプル
次の例では、データ ソースは共通テナントを使用してグローバル クラウドの Azure AD をサポートしています (Azure B2B はサポートしていません)。
Authentication = [
Aad = [
AuthorizationUri = "https://login.microsoftonline.com/common/oauth2/authorize",
Resource = "77256ee0-fe79-11ea-adc1-0242ac120002" // Azure AD resource value for your service - Guid or URL
]
]
次の例では、データ ソースは OpenID Connect (OIDC)、またはそれに類似するプロトコルに基づいてテナント検出をサポートしています。 これにより、コネクタは、データ ソース パス内の 1 つ以上のパラメーターに基づいて、使用する Azure AD エンドポイントを正しく判断できるようになっています。 この動的な検出アプローチにより、コネクタが Azure B2B をサポートできるようになっています。
// Implement this function to retrieve or calculate the service URL based on the data source path parameters
GetServiceRootFromDataSourcePath = (dataSourcePath) as text => ...;
GetAuthorizationUrlFromWwwAuthenticate = (url as text) as text =>
let
// Sending an unauthenticated request to the service returns
// a 302 status with WWW-Authenticate header in the response. The value will
// contain the correct authorization_uri.
//
// Example:
// Bearer authorization_uri="https://login.microsoftonline.com/{tenant_guid}/oauth2/authorize"
responseCodes = {302, 401},
endpointResponse = Web.Contents(url, [
ManualCredentials = true,
ManualStatusHandling = responseCodes
])
in
if (List.Contains(responseCodes, Value.Metadata(endpointResponse)[Response.Status]?)) then
let
headers = Record.FieldOrDefault(Value.Metadata(endpointResponse), "Headers", []),
wwwAuthenticate = Record.FieldOrDefault(headers, "WWW-Authenticate", ""),
split = Text.Split(Text.Trim(wwwAuthenticate), " "),
authorizationUri = List.First(List.Select(split, each Text.Contains(_, "authorization_uri=")), null)
in
if (authorizationUri <> null) then
// Trim and replace the double quotes inserted before the url
Text.Replace(Text.Trim(Text.Trim(Text.AfterDelimiter(authorizationUri, "=")), ","), """", "")
else
error Error.Record("DataSource.Error", "Unexpected WWW-Authenticate header format or value during authentication."), [
#"WWW-Authenticate" = wwwAuthenticate
])
else
error Error.Unexpected("Unexpected response from server during authentication."));
<... snip ...>
Authentication = [
Aad = [
AuthorizationUri = (dataSourcePath) =>
GetAuthorizationUrlFromWwwAuthenticate(
GetServiceRootFromDataSourcePath(dataSourcePath)
),
Resource = "https://myAadResourceValue.com", // Azure AD resource value for your service - Guid or URL
]
]
データ ソース パス
M エンジンは、その Kind と Path の組み合わせを使用して、データ ソースを識別します。 クエリ評価中にデータソースが検出されると、M エンジンは一致する資格情報を見つけようとします。 資格情報が見つからない場合、エンジンは特別なエラーを返し、Power Query で資格情報プロンプトが表示されます。
Kind 値は、Data Source Kind 定義から取得されます。
Path 値は、データ ソース関数の必須パラメーターから導出されます。 省略可能なパラメーターは、データ ソース パス識別子に考慮されません。
その結果、データ ソースの種類に関連付けられている、すべてのデータ ソース関数は、同じパラメーターを持っている必要があります。
タイプ Uri.Type が単一パラメーターを持つ関数には、特別な処理があります。 詳細については、この後のセクションをご覧ください。
Power BI Desktop の [データ ソース設定] ダイアログで、資格情報がどのように保存されるかの例を確認できます。 このダイアログでは、Kind はアイコンで表され、Path 値はテキストとして表示されます。

注意
開発中にデータ ソース関数の必須パラメーターを変更すると、以前に保存された資格情報は機能しなくなります (パス値が一致しなくなるため)。 データ ソース関数のパラメーターを変更するときはいつでも、保存されている資格情報を削除する必要があります。 互換性のない資格情報が見つかった場合、ランタイムでエラーが発生する可能性があります。
データ ソース パスの形式
データ ソースの Path 値は、データ ソース関数の必須パラメーターから導出されます。
関数のメタデータに DataSource.Path = false を追加することで、必須パラメーターをパスから除外することもできます (下記を参照)。
既定では、実際の文字列値は、Power BI Desktop の [データ ソース設定] ダイアログと資格情報プロンプトで確認できます。
Data Source Kind 定義に Label 値が含まれている場合は、代わりにラベルの値が表示されます。
たとえば、HelloWorldWithDocs サンプルのデータ ソース関数には、次の署名があります。
HelloWorldWithDocs.Contents = (message as text, optional count as number) as table => ...
この関数には、タイプ text の単一の必須パラメーター (message) があり、データ ソース パスの計算に使用されます。 省略可能なパラメーター (count) は無視されます。 パスは次のように表示されます
資格情報プロンプト:

データ ソース設定 UI:

ラベル値が定義されている場合、データ ソース パスの値は表示されません。

注意
ユーザーが入力したさまざまな資格情報を区別できなくなるため、関数に必須パラメーターがある場合は、現在、データ ソースのラベルを 含めない ことをお勧めします。 今後はこの点を改善して、データ コネクタが独自のカスタム データ ソース パスを表示できるようにしたいと考えています。
データ ソース パスからの必須パラメーターの除外
関数パラメーターを必須にしたいが、データ ソース パスの一部には含めたくないという場合は、関数ドキュメントのメタデータに DataSource.Path = false を追加できます。
このプロパティは、関数の 1 つ以上のパラメーターに追加できます。 このフィールドを指定すると、データ ソース パスからその値が削除されます (つまり、TestConnection 関数に渡されなくなります)。そのため、これらの値は、データ ソースを識別したり、ユーザーの資格情報を区別したりするために、必須以外のパラメーターにだけ使用するようにしてください。
たとえば、HelloWorldWithDocs サンプルのコネクタでは、異なる message 値に対して異なる資格情報が必要になります。
message パラメーターに DataSource.Path = false を追加すると、その値がデータ ソース パスの計算から除外され、コネクタは実質的に "シングルトン" になります。 HelloWorldWithDocs.Contents へのすべての呼び出しは同じデータ ソースとして扱われるので、ユーザーは資格情報を 1 回だけ指定することになります。
HelloWorldType = type function (
message as (type text meta [
DataSource.Path = false,
Documentation.FieldCaption = "Message",
Documentation.FieldDescription = "Text to display",
Documentation.SampleValues = {"Hello world", "Hola mundo"}
]),
optional count as (type number meta [
Documentation.FieldCaption = "Count",
Documentation.FieldDescription = "Number of times to repeat the message",
Documentation.AllowedValues = { 1, 2, 3 }
]))
as table meta [
Documentation.Name = "Hello - Name",
Documentation.LongDescription = "Hello - Long Description",
Documentation.Examples = {[
Description = "Returns a table with 'Hello world' repeated 2 times",
Code = "HelloWorldWithDocs.Contents(""Hello world"", 2)",
Result = "#table({""Column1""}, {{""Hello world""}, {""Hello world""}})"
],[
Description = "Another example, new message, new count!",
Code = "HelloWorldWithDocs.Contents(""Goodbye"", 1)",
Result = "#table({""Column1""}, {{""Goodbye""}})"
]}
];
Uri パラメーターを含む関数
Uri ベースの識別子を持つデータ ソースは非常に一般的であるため、Uri ベースのデータ ソース パスを処理する場合、Power Query UI には特別な処理があります。 Uri ベースのデータ ソースが検出されると、資格情報ダイアログにドロップダウンが表示され、ユーザーは完全なパス (およびその間のすべてのパス) ではなく、ベース パスを選択できます。

Uri.Typeは M 言語の プリミティブ型 ではなく、指定の型 であるため、Value.ReplaceType 関数を使用して、テキスト パラメーターを Uri として扱う必要があることを示す必要があります。
shared GithubSample.Contents = Value.ReplaceType(Github.Contents, type function (url as Uri.Type) as any);
その他の認証の種類
Kerberos ベースのシングル サインオンなど、この記事で説明されていないその他の種類の認証について詳しくは、追加のコネクタ機能に関する記事を参照してください。