KeycloakでMicrosoft 365/SharePointにSSOする方法|ダイレクト フェデレーションのAADSTS90019対処

Keycloak を外部 IdP として Microsoft 365/SharePoint Online に SSO しようとしたとき、AADSTS90019 が出て先に進めないケースがあります。この記事では「ダイレクト フェデレーション」の前提整理から、URL・クレーム・ドメインのズレで起きやすい落とし穴、Keycloak/Microsoft Entra 側での具体的な確認ポイントまで、実務目線でまとめます。

目次

AADSTS90019 とは何か(結論:テナントの判別に失敗している)

エラー AADSTS90019 は、Microsoft Entra ID が「このサインイン要求をどのテナントとして処理すべきか」を特定できないときに出る代表的なエラーです。Microsoft のエラーコード定義では MissingTenantRealm(テナント識別子を要求から判別できない)に該当します。

SSO の設定がどれだけ正しく見えても、次のどこかで「テナント情報(テナントID・テナント名・ドメインなど)」が欠けたり矛盾すると、Entra 側が宛先テナントを決められずに止まります。

  • アクセスしているサインイン URL(テナント固有/共通)
  • SAML の Issuer/Audience/Recipient(ACS) の一致
  • メールアドレス(UPN相当)のドメインが、想定されるテナント(またはフェデレーション対象)に紐づくか

最初に整理:あなたがやりたいのは「どの連携方式」か

Keycloak と Microsoft 365/SharePoint の SSO で混乱が起きやすいのは、「似た言葉で別物の方式」が存在するからです。まず目的別に、どれを選ぶべきか整理します。

方式主な用途対象ユーザーEntra 側の設定場所ユーザー事前作成典型的な落とし穴
ダイレクト フェデレーション(SAML/WS-Fed IdP フェデレーション)外部組織の IdP を使ってゲスト/外部ユーザーがサインインパートナー/ゲスト(B2B)Entra ID → External Identities → All identity providers(カスタム)原則不要(後述)テナント種別(workforce/external)で ACS が違う、必須クレーム不足
エンタープライズ アプリ(SAML SSO)Entra が IdP になって SaaS へ SSO主に社内ユーザー(メンバー)Entra ID → Enterprise applications → Single sign-on(SAML)必要(Entra に存在するユーザーで SSO)「Entra が IdP」なので、Keycloak を IdP にしたい目的とズレる
(補足)M365 向けのドメイン フェデレーションMicrosoft 365 そのものの認証を外部 IdP に委任社内ユーザー(メンバー)ドメイン認証(PowerShell/Graph 等)必要(メンバーとして存在)SP Entity ID が固定など、仕様制約が多い

この記事で扱う「ダイレクト フェデレーション」は、主に外部ユーザー(B2B)のサインイン体験を Keycloak に寄せるための仕組みです。Microsoft Learn でも、SAML/WS-Fed IdP フェデレーションは「招待の引き換え(invitation redemption)やセルフサービス サインアップ」で外部ユーザーが自分の IdP でサインインできる、と説明されています。

重要:Entra の「workforce テナント」か「external テナント」かで前提が変わる

Microsoft Entra External ID には大きく workforce テナント(従業員+組織リソースのある通常の Entra)と、external テナント(CIAM 用の別テナント)があります。ここを取り違えると、URL(ACS)が合わずに AADSTS90019 を含むエラーに直行しがちです。

項目workforce テナントexternal テナント(CIAM)
主目的従業員と組織リソース、B2B 共同作業外部向けアプリ(顧客/消費者)のサインイン体験
Microsoft 365/SharePoint への SSO対応非対応(Microsoft 365 などの Microsoft 1st party への SSO はサポート外)
ダイレクト フェデレーションの ACS(外部 IdP 側に設定する値)https://login.microsoftonline.com/login.srfhttps://<tenantID>.ciamlogin.com/login.srf

Microsoft 365/SharePoint Online を対象にしているなら、基本はworkforce テナントが前提になります。external テナント側の値(ciamlogin.com)を使っている場合は、まずここを疑ってください。

結論:ダイレクト フェデレーションでは「ユーザーを Entra に事前作成」は原則不要

質問で一番多いのが「この構成だと、Keycloak 側ユーザーを Entra(Azure AD)に事前作成しないといけないのか?」ですが、ダイレクト フェデレーション(B2B)前提なら原則不要です。

ただし誤解しやすいポイントがあります。“ユーザーオブジェクトが不要” ではありません。B2B コラボレーションでは、認証方法が何であっても(OTP でも SAML フェデレーションでも)、リソース側テナントにはゲストのユーザーオブジェクトが作成され、これを使ってグループやアプリ、SharePoint サイトへの権限付与を行います。

つまり運用感としては次のイメージです。

  • 認証(Authentication):Keycloak(外部 IdP)で実施
  • 認可(Authorization):Entra 側に作られるゲスト(ユーザーオブジェクト)で制御
  • 作成タイミング:招待の引き換え(invitation redemption)やセルフサービス サインアップ等のフローで作られる

AADSTS90019 が出やすい原因を「構成のどこでズレたか」で絞り込む

AADSTS90019 は原因が一つではありませんが、Keycloak×ダイレクト フェデレーション周りでは「テナント識別に必要な情報が、URL か SAML のどこかで欠けている/食い違っている」ケースが大半です。

よくある原因何が起きているか確認ポイント対処
workforce/external テナントを取り違えACS が別物なので、Entra が受け付けない/別のフローに飛ぶ外部 IdP(Keycloak)に設定した ACS が ciamlogin.com になっていないかMicrosoft 365 なら login.microsoftonline.com/login.srf 側(workforce)に合わせる
必須クレーム(emailaddress)が不足/名前が違うEntra がユーザーやドメインを解決できず、テナント判別にも失敗しやすいSAML アサーションに http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress が入っているかKeycloak のプロトコルマッパーで「URI 形式の属性名」で送出する
Audience / Issuer / Recipient(ACS) の不一致要求と応答が紐づかず、Entra が処理できないEntra 設定値と 1 文字でも違わないか(大小文字・末尾スラッシュ含む)トレース結果を“正”として、Keycloak/Entra を一致させる
AuthnRequest の Issuer(SP Entity ID)に Keycloak が合っていないKeycloak が別クライアントとして扱い、想定外の応答になるSAML-tracer で AuthnRequest の Issuer を実値で確認Keycloak のクライアント ID(Entity ID)を実際の Issuer に合わせる(後述)
プレースホルダーのまま運用({tenant} など)tenant context が欠落し、MissingTenantRealm に寄りやすい設定画面・メタデータの URL に {tenant} が残っていないかテナント ID(GUID)またはテナント名で確定させる
サインイン開始 URL が “共通” で、テナント誘導ができていないユーザー入力やヒントがないと、どのテナントか決められないユーザーがどこからサインインを開始しているかworkforce なら tenantid 付きの導線(MyApps など)を使う

Microsoft が要求する「必須の SAML 属性・クレーム」を先に固定する

ダイレクト フェデレーションでは、外部 IdP(Keycloak)が返す SAML 応答に必須の形式があります。Microsoft Learn では、SAML 2.0 の場合に少なくとも以下を求めています。

  • NameID Format:urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
  • emailaddress クレーム:http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress(ユーザーのメールアドレス)
  • ACS(AssertionConsumerService):テナント種別に応じた login.srf エンドポイント
  • Audience:https://login.microsoftonline.com/<tenant ID>/(推奨)

ここで重要なのは、あなたの Keycloak 側で使っている属性名が IDPEmail などの独自名になっていても、Entra が期待する名前(URI)で送られていないと、Entra 側が読めない可能性が高い、という点です。

Keycloak 側の設定ポイント(SAML クライアント)

Keycloak では「Microsoft(Entra)を Service Provider とみなす SAML クライアント」を作る形になります。以下は実務での“事故りやすい”項目を、SAML-tracer の確認観点とセットでまとめたチェック表です。

Keycloak 設定項目推奨・注意点SAML トレースで見る場所
Client ID(SP Entity ID)まずは AuthnRequest の Issuer 実値に合わせるのが最優先です。 ドメインレベル(Microsoft 365 など)では urn:federation:MicrosoftOnline が使われるケースがあり、変更できない旨の案内もあります。AuthnRequest の <saml:Issuer>
ACS URL(Recipient / Destination)テナント種別により固定。Microsoft 365/SharePoint 前提なら workforce の login.microsoftonline.com/login.srf に合わせる。SAML Response の Destination/Recipient
NameID Formatpersistent を指定。値はユーザーごとに一意で、変わりにくい識別子にする。Assertion 内 <Subject><NameID>
emailaddress クレーム属性名を http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress(URI)で送る。 値は user@domain 形式で、ドメイン部分が意図したフェデレーション条件と合っていることが重要。AttributeStatement 内の属性名と値
署名(Signature)少なくとも SAML Response(または Assertion)へ署名し、Entra に登録した証明書と一致させる。ローテーション運用も考慮する。Response/Assertion の署名有無、証明書
時刻(NotBefore/NotOnOrAfter)Keycloak と Entra の時計ズレがあると弾かれる。NTP 同期を推奨。Conditions の時刻

Keycloak で emailaddress クレームを送る具体例

Keycloak の「Protocol Mapper」を使い、メールアドレスを SAML 属性として送るときは、属性名を URI で合わせるのがポイントです。概念的には次のような形を目指します。

<saml2:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
  <saml2:AttributeValue>[email protected]</saml2:AttributeValue>
</saml2:Attribute>

既存の IDPEmail のような独自属性を送っていても、それだけでは Entra 側が必須クレームとして扱わない可能性があります。Microsoft Learn の必須クレーム定義に合わせてください。

Entra 側の設定ポイント(ダイレクト フェデレーション)

Entra 側では「外部 IdP(SAML/WS-Fed)」を登録し、どのドメインのユーザーをその IdP に誘導するかを設定します。Microsoft Learn では、外部 IdP を追加する手順や、必要なメタデータ(Issuer URI、パッシブ認証エンドポイント、証明書、メタデータ URL 等)を指定する流れが示されています。

よくある “Entra 側のズレ”

  • Issuer URI:Keycloak Realm の Entity ID と一致していない
  • Sign-in URL(Passive authentication endpoint):Keycloak の SAML エンドポイントと一致していない
  • 証明書:Keycloak が署名に使っている証明書と Entra 登録が一致していない(ローテーション後に放置など)
  • テナント種別の取り違え:workforce と external で ACS が違うのに同じ値を使っている

外部組織の IdP URL とドメインが違う場合の DNS TXT レコード

パートナー側の IdP のエンドポイントが対象ドメインと一致しない場合、DNS に TXT レコードを追加して証明するフローが必要になることがあります。Microsoft Learn では TXT レコード例(DirectFedAuthUrl=...)が提示されています。

example.com. IN TXT DirectFedAuthUrl=https://idp.example.net/sso

「Client ID: urn:federation:MicrosoftOnline」は正しいのか問題

この値は昔からよく出てくるため混乱しがちですが、ポイントはあなたのシナリオが「ドメインレベル(Microsoft 365 など)」なのか、「外部 IdP フェデレーション(B2B)」なのかで見え方が変わることです。

  • Microsoft の案内では、ドメインレベルのフェデレーションでは SP Entity ID が urn:federation:MicrosoftOnline(グローバル)として扱われ、テナント固有の Entity ID に変更できない、という回答があります。
  • 一方で、外部 IdP フェデレーション(SAML/WS-Fed IdP federation)のドキュメントでは、SAML 応答の Audience をテナント ID を含む値にする推奨や、必要な属性・クレームが整理されています。

実務的に一番安全なのは、SAML-tracer で “実際に Entra から飛んできた AuthnRequest の Issuer” を見て、それを Keycloak のクライアント ID に合わせることです。ドキュメントやブログに書いてある値より、あなたの環境で飛んでいる値が正です。

トラブルシューティング:SAML-tracer で必ず見るべきポイント

AADSTS90019 を潰すときは、設定画面を眺めるよりも「飛んでいる SAML を見て差分をなくす」ほうが速いです。以下のチェックリストで、ズレの箇所を機械的に消していきます。

チェック項目見る場所OK の目安
サインイン開始 URL にテナント情報が含まれるかブラウザのアドレス、遷移ログworkforce なら tenantid を含む導線(MyApps 等)も活用できる
AuthnRequest の IssuerKeycloak に入る AuthnRequestKeycloak クライアント ID と一致
SAML Response の Destination / RecipientKeycloak から返す ResponseACS(login.srf)と完全一致
AudienceRestrictionAssertion 内https://login.microsoftonline.com/<tenantID>/ 等、Entra 側が期待する値
NameID Format / 値Subjectpersistent で一意、変わりにくい値
emailaddress クレームAttributeStatementURI 名で存在し、値が user@domain 形式
署名と証明書署名要素Entra に登録した証明書と一致(期限・ローテも確認)

「サインイン導線」も地味に重要(共通エンドポイントの挙動)

workforce テナントの場合、SAML/WS-Fed IdP フェデレーションユーザーは、テナント情報を含まない共通エンドポイントからでもサインインできますが、その場合は途中で「組織にサインイン」などの選択を経て、テナントを特定していく挙動になります。テナント情報を明示した URL(例:MyApps の tenantid 付き)を使うと、テナント特定が安定しやすく、切り分けが楽になります。

「どこからサインインを開始したか」は、AADSTS90019 のような“テナント判別系エラー”では特に効きます。ユーザーにブックマークや古いリンクが混ざっているだけで再現することもあるため、再現手順に使った URL は必ず控えておくのがおすすめです。

それでも直らない場合の切り分け(運用で詰まるポイント)

  • Entra のサインインログ:エラーコード以外の Failure reason、Correlation ID を確認(サポート問い合わせにも必須)
  • Keycloak のサーバーログ:AuthnRequest をどのクライアントで受けたか、署名・宛先チェックで弾いていないか
  • 証明書ローテーション:IdP の署名証明書が更新されたのに Entra 側が追従していない(メタデータ URL 未設定など)
  • テナント種別の再確認:external テナントで Microsoft 365 へ SSO しようとしていないか(仕様として不可)

まとめ:AADSTS90019 を最短で潰すための優先順位

  • テナント種別(workforce / external)を確定し、ACS(login.srf)を正しい列の値に合わせる
  • Keycloak から emailaddress クレーム(URI 名) を必ず送る
  • SAML-tracer で Issuer / Audience / Recipient を実値比較し、1 文字単位で一致させる
  • ダイレクト フェデレーション(B2B)なら、ユーザーの手動事前作成は原則不要だが、権限付与のためのゲストオブジェクトは作成される(招待/サインアップの流れで)

ダイレクト フェデレーションは「認証を外に出す」だけでなく、「外部ユーザーの導線」「必須クレーム」「テナント種別」まで含めて初めて成立します。AADSTS90019 は派手ですが、原因はたいてい “どこか一つの値がズレているだけ” です。トレースで実値を見て、上から順に潰していけば再現性高く解決できます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次