Azure SQL Database を Microsoft Entra 認証(旧 Azure AD)で使おうとして、DefaultAzureCredential でアクセストークンは取得できるのに、接続時だけ Login failed for user '' で失敗する――。.NET Framework 4.8 ではこの症状が起きやすく、接続文字列の認証指定とコード側のトークン注入が噛み合っていないケースが原因になりがちです。
症状:トークン取得は成功するのに「Login failed for user ”」
現象としては、次のような流れになります。
DefaultAzureCredentialでhttps://database.windows.net/.defaultのトークン取得は成功する- しかし
SqlConnection.Open()でMicrosoft.Data.SqlClient.SqlException: 'Login failed for user '''が発生する - エラーメッセージ上、ユーザー名が空文字(
'')扱いになっている
「トークンは取れているのに、なぜログインできないのか?」と混乱しやすいのですが、ここがポイントです。
- トークン取得が成功しても、それが “SQL 接続で使われる” とは限りません。
- SQL の接続処理は、接続文字列(Authentication 指定)やドライバのモードに強く依存します。
結論:.NET Framework 4.8 では「Authentication=Active Directory Default」に寄せる
この問題の解決として一番安定しやすいのが、接続文字列側で Microsoft Entra 認証方式を明示し、コード側の手動トークン注入をやめることです。
やること(解決策)
- 接続文字列に
Authentication=Active Directory Defaultを追加する connection.AccessTokenにトークンを入れるコードを削除する(混在をやめる)
削除する(不要になる)コード例
次のような “取得したトークンを手動で注入する” 実装は外します。
var credential = new DefaultAzureCredential();
var tokenRequestContext = new TokenRequestContext(
new[] { "https://database.windows.net/.default" }
);
var token = credential.GetToken(tokenRequestContext);
connection.AccessToken = token.Token;
「トークンは取れているのに失敗する」ケースほど、この “手動注入” と “接続文字列側の認証指定(または未指定)” がチグハグになっていることが多いです。
なぜ「Login failed for user ”」になるのか(原因の考え方)
Login failed for user '' は、ざっくり言うと「SQL 認証としてログインしようとしているが、ユーザー名が空」という形で失敗している状態を表します。
Microsoft Entra 認証で接続したい場合、本来は「ユーザー名・パスワード」ではなく、Entra 由来のトークンで SQL へのログイン(Federated/AAD 系のフロー)が走るべきです。
ところが、次のように “認証方式が混在” すると、ドライバの解釈がブレて期待どおりにならないことがあります。
| 混在パターン | 起きやすいこと | 結果として見える症状 |
|---|---|---|
| コードで AccessToken を入れるが、接続文字列で Authentication を指定しない | SQL 認証(User ID/Password)の流れで接続しようとする/トークンを使うモードに入らない | Login failed for user '' など、SQL認証っぽい失敗 |
| 接続文字列で別の Authentication を指定している(または古い例をコピペしている) | ドライバ内部の認証フローと、手動注入が競合する | ユーザーが空、トークンが無視されたように見える等 |
| .NET Framework 側の実装都合で、思った通りの認証経路になっていない | 取得は成功しても利用されない/別経路を選ぶ | 「取れてるのに繋がらない」状態 |
つまり、「トークン取得の成功」と「SQL 接続でそのトークンが使われる」は別問題です。そこで、.NET Framework 4.8 では特に“接続文字列で Authentication=Active Directory Default を明示して、ドライバに一任する”方が事故が減ります。
最小構成:.NET Framework 4.8 で動く接続例(Authentication=Active Directory Default)
以下は “混在を避ける” ことにフォーカスした最小例です。ポイントは、AccessToken を触らないことです。
接続文字列の例
Server=tcp:<サーバー名>.database.windows.net,1433;
Database=<DB名>;
Encrypt=True;
TrustServerCertificate=False;
Connection Timeout=30;
Authentication=Active Directory Default;
WordPress に貼り付ける用途を考えると1行の方が管理しやすいので、実運用では次のように整形してもOKです。
Server=tcp:<サーバー名>.database.windows.net,1433;Database=<DB名>;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Authentication=Active Directory Default;
C# コード例(AccessToken を触らない)
using System;
using Microsoft.Data.SqlClient;
public class Program
{
public static void Main()
{
var connectionString =
"Server=tcp:<サーバー名>.database.windows.net,1433;" +
"Database=;" +
"Encrypt=True;" +
"TrustServerCertificate=False;" +
"Connection Timeout=30;" +
"Authentication=Active Directory Default;";
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT SUSER_SNAME(), DB_NAME()";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("SUSER_SNAME(): " + reader.GetString(0));
Console.WriteLine("DB_NAME(): " + reader.GetString(1));
}
}
}
}
}
}
「Authentication=Active Directory Default」+「AccessToken を自前で入れない」という形に揃えると、SqlClient 側が適切なフローでトークン取得〜接続まで面倒を見てくれます。
事前設定チェック(よくある設定漏れを体系的に潰す)
質問の前提として多くは対策済みでも、チーム開発や環境差で抜けがちなので、チェック表としてまとめます。特に “サーバー側で Entra 管理者が設定されているか” は最重要です。
| チェック項目 | どこで設定するか | 確認ポイント |
|---|---|---|
| Azure SQL Server に Entra 管理者(Active Directory admin)を設定 | Azure Portal(SQL Server) | 設定されていないと、DB 側で Entra ユーザー作成や外部プロバイダー関連が詰む |
| DB に対象ユーザー/グループ/マネージドIDを作成 | SQL(master ではなく対象DB) | CREATE USER ... FROM EXTERNAL PROVIDER が基本 |
| DB ロール付与 | SQL | db_datareader / db_datawriter など必要最小限に |
| 接続元 IP をファイアウォールで許可 | Azure Portal(SQL Server の networking) | ローカル開発PC・ビルドサーバー・App Service など環境ごとに差が出る |
| アプリの実行環境で Entra の認証情報が取れる | ローカル/サーバー | Azure CLI ログイン、Visual Studio サインイン、Managed Identity など |
DB ユーザー作成と権限付与の例
例として、Entra ユーザー(またはグループ)を DB に作る場合の SQL は次のようになります。
-- 対象データベースで実行
CREATE USER [[email protected]] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [[email protected]];
ALTER ROLE db_datawriter ADD MEMBER [[email protected]];
個人ユーザーを直に割り当てるより、運用ではEntra グループを DB ユーザーとして作って、メンバー管理を Entra 側に寄せる方が権限管理が楽になります(入退社・異動・委託先の入れ替えなど)。
「Active Directory Default」とは何か(DefaultAzureCredential と混同しない)
Authentication=Active Directory Default は、SqlClient 側が “実行環境に応じて” 認証手段を選ぶ方式です。ローカル開発と本番(Azure 上)で同じコードを動かしたい場合に相性がよく、手動でトークンを注入するより事故が減ります。
実務での感覚として、次のような使い分けになります。
| 実行環境 | 狙いたい認証の形 | おすすめの考え方 |
|---|---|---|
| 開発者PC(Visual Studio / Azure CLI) | 開発者のサインイン情報で接続 | 接続文字列は Authentication=Active Directory Default、権限は Entra グループで付与 |
| Azure App Service / Functions / VM | Managed Identity で接続 | 本番は Managed Identity を前提にし、DB 側でその ID に権限を付与する |
| オンプレ/他クラウド | サービスプリンシパル等を使うことも | 証明書/シークレット管理とローテを設計し、必要なら方式を固定する |
ここで重要なのは、“どの認証フローにするかを、コードと接続文字列で二重管理しない”ことです。特に .NET Framework 4.8 では、互換性や実装差の影響を受けやすく、混在が原因でドライバの挙動が読みにくくなります。
今回のハマりどころ:トークン注入と接続文字列の「二重管理」
問題の本質は次の1点に集約できます。
認証方式を「コードで手動」+「接続文字列で別方式(または未指定)」のように混在させると、期待どおりに Entra 認証として扱われず、結果的に Login failed for user '' になり得る。
実際、コード側でトークンを取れていると「認証は成功している」と錯覚しがちですが、SQL 接続で重要なのは “接続時にドライバがどの方式としてログイン処理を組み立てたか” です。
そのため、次のどちらかに寄せるのが筋が良いです。
- 方式A(推奨):接続文字列で
Authentication=Active Directory Defaultを指定し、ドライバに任せる - 方式B(上級者向け):手動で AccessToken を注入する場合は、その方式に合わせた Authentication 指定・運用設計をする
今回のケースは方式Aが最短で安定しやすい解です。
「Authentication=Active Directory Default」に寄せると何が嬉しいのか
単に “繋がる” だけでなく、運用上のメリットも大きいです。
- 認証フローの一貫性:接続文字列が「Entra で繋ぐ宣言」になり、レビューで見落としにくい
- 実装が薄くなる:トークン取得・更新・例外パターンの吸収をドライバに寄せられる
- 環境差に強い:ローカルは開発者資格情報、本番は Managed Identity といった切り替えがしやすい
- セキュリティ事故を減らす:トークンをログ出力してしまう、キャッシュして漏れる等のミスを避けやすい
特に .NET Framework 4.8 の保守案件では、「シンプルな接続文字列」+「薄いコード」に寄せる方が長期運用で効いてきます。
追加のトラブルシュート:同じ症状に見えて別原因のケース
Login failed for user '' が出たとき、まずは “混在” を疑うのが最短ですが、周辺要因が重なることもあります。切り分けしやすいように、ありがちなパターンを表にまとめます。
| エラー/症状 | 疑うポイント | 対処の方向性 |
|---|---|---|
Login failed for user '' | 認証方式の混在、Authentication 未指定、User ID が空のまま | Authentication=Active Directory Default に寄せ、AccessToken 注入を外して統一 |
| 接続はするが権限不足(SELECT/INSERT で拒否) | DB ロール付与漏れ、対象がユーザーではなくグループ/ID | DB 側のユーザー作成と ALTER ROLE ... ADD MEMBER を見直す |
| ファイアウォール系の拒否 | IP許可漏れ、環境ごとに送信元が違う | Azure SQL の firewall 設定を再確認(開発PC/CI/本番で分ける) |
| TLS/SSL 関連の例外 | .NET Framework 実行環境の TLS 設定、古いOS/暗号スイート | Encrypt=True を前提に、OS/ランタイムの TLS 1.2 以上の前提を満たす |
| ローカルは繋がるが本番だけ繋がらない | 本番で Default の認証経路が変わっている(Managed Identity 無効など) | 本番環境でどの資格情報が使われる前提かを決め、Managed Identity の有効化と DB 権限を整える |
「まずは認証方式を統一」→「DB 側のユーザー/ロール」→「ネットワーク(ファイアウォール)」の順に潰すと、遠回りしにくいです。
どうしても “手動トークン注入” を続けたい場合の注意点
今回の解決策は “注入コードを削除” ですが、事情があって手動注入を選びたいケースもあります(例:トークン取得を中央集権的に管理している、特殊な認証経路を通すなど)。その場合は、次の点だけは押さえてください。
- 手動注入をするなら、接続文字列もその方式に合わせて固定する(「未指定」や「別方式」を混ぜない)
- トークンの更新・有効期限を考慮する(長時間プロセス、バッチ、常駐アプリで特に重要)
- 接続プールの挙動を理解する(トークンの差し替えタイミング、同一接続文字列での再利用など)
- ログにトークンを出さない(例外ログやデバッグログに混ざる事故が起きやすい)
ただし、保守性と事故率を考えると、.NET Framework 4.8 の一般的な業務アプリでは「Authentication=Active Directory Default に寄せる」方が無難です。
本番運用でのおすすめ設計(再発防止の観点)
最後に、今回のような “繋がる/繋がらない” を繰り返さないための現実的な運用ポイントをまとめます。
権限は「個人」ではなく「グループ」か「Managed Identity」に寄せる
- 開発・検証は Entra グループで DB ロールを付与し、メンバー管理を Entra 側に寄せる
- 本番は可能なら Managed Identity を採用し、シークレット管理を排除する
接続文字列は “認証方式が一目で分かる” 形にする
- Entra 認証の場合は
Authentication=Active Directory Defaultを明示 - SQL 認証と同居させない(同一アプリ内で両方を使う場合も、設定を明確に分ける)
切り分け用の簡易クエリを用意しておく
障害時に「誰としてログインできているか」を確認できると早いです。
SELECT
SUSER_SNAME() AS login_name,
ORIGINAL_LOGIN() AS original_login,
DB_NAME() AS database_name;
アプリ側でこの結果を一時的にログに出せるようにしておくと、権限の付け間違い(ユーザー/グループ/ID の取り違え)に気付きやすくなります。
まとめ
DefaultAzureCredentialでトークン取得が成功しても、SQL 接続でそのトークンが使われるとは限らない- .NET Framework 4.8 で
Login failed for user ''が出るときは、認証方式の混在をまず疑う - 最短で安定させるなら、接続文字列に
Authentication=Active Directory Defaultを入れて、AccessToken手動注入コードを削除 - 併せて、DB 側の
CREATE USER ... FROM EXTERNAL PROVIDERとロール付与、ファイアウォール許可をチェックする

コメント