Microsoft Entra PIM for Groups で Microsoft Graph の「List assignmentScheduleInstances」をアプリケーション権限(クライアント資格情報フロー)で呼ぶと、403/404 で詰まることがあります。実はこの API はアプリ権限でも利用でき、いくつかの前提条件を満たすかどうかで結果が大きく変わります。
この記事の前提:何が「動かない」と見えているのか
本記事で扱うのは、次のような状況です。
- Entra ロール(ディレクトリ ロール)の PIM では、アプリケーション権限で
/roleManagement/directory/roleAssignmentScheduleInstancesを呼べている。 - 同じ発想で PIM グループ(Azure AD / Microsoft Entra グループ)の「現在アクティブな割り当て」を取得しようとすると、アプリケーション権限だと失敗し、委任権限(ユーザー トークン)だと成功する。
- ドキュメントには
PrivilegedAssignmentSchedule.Read.AzureADGroupを付ければアプリ権限でも呼べると書かれているのに、実環境では 403/404 や空結果になり「権限が無い」ように見える。
結論:PIM グループでもアプリケーション権限で利用できる
List assignmentScheduleInstances は PIM for Groups(PIM グループ)でもアプリケーション権限で利用できます。ただし、権限設定・トークンの中身・グループ側の状態のいずれかが欠けると、403/404/空配列になって「動かない」と誤解しやすいのが落とし穴です。
| チェック観点 | 満たしていないと起きやすい症状 | まず見るポイント |
|---|---|---|
| 管理者同意(Admin consent) | 403 Forbidden(insufficient privileges) | API のアクセス許可が「管理者の同意済み」になっているか |
| トークンが app-only(roles クレーム)になっているか | 403 / 401、または「権限が入っていない」 | JWT の roles に必要な権限が入っているか |
| 対象グループが PIM for Groups の管理対象か | 404 / 空配列(権限エラーに見える) | ポータルでグループが PIM の「Groups」に表示されるか |
| アクティブ割り当てが存在するか | 200 OK だが value が空 | ポータルや別 API で割り当てがあるか |
まず整理:Entra ロールの PIM と、PIM for Groups は API も権限も別
「どちらも PIM だから同じエンドポイントで取れるはず」と考えると混乱します。実際には、Entra ロールと PIM グループは Microsoft Graph 上で入口が分かれています。
| 対象 | 代表エンドポイント | 取得できるもの | 最小のアプリ権限(例) | 注意点 |
|---|---|---|---|---|
| Entra ロール(ディレクトリ ロール)のアクティブ割り当て | GET /roleManagement/directory/roleAssignmentScheduleInstances | テナント内のアクティブなロール割り当てインスタンス | RoleAssignmentSchedule.Read.Directory | フィルター無しでも呼べるが、件数が多い場合は $filter で絞ると運用が楽 |
| PIM for Groups(PIM グループ)のアクティブ割り当て | GET /identityGovernance/privilegedAccess/group/assignmentScheduleInstances | グループのメンバー/オーナーのアクティブ割り当てインスタンス | PrivilegedAssignmentSchedule.Read.AzureADGroup | この API は $filter が必須(groupId か principalId でスコープする) |
特に PIM グループ側は、API の仕様として $filter(eq)で groupId または principalId を必ず指定します。フィルター無しで呼ぶと「アプリ権限がダメなのかも?」ではなく、単に要求条件を満たしていないだけ、というケースがあります。
呼び出しの基本:List assignmentScheduleInstances の正しい URL とフィルター
PIM グループの「現在アクティブな割り当て(スケジュール インスタンス)」を取得する基本形は次の 2 パターンです。
特定グループのアクティブ割り当てを一覧する(groupId で絞る)
GET https://graph.microsoft.com/v1.0/identityGovernance/privilegedAccess/group/assignmentScheduleInstances?$filter=groupId eq '{グループのObjectId}'
特定ユーザー(principal)のアクティブ割り当てを一覧する(principalId で絞る)
GET https://graph.microsoft.com/v1.0/identityGovernance/privilegedAccess/group/assignmentScheduleInstances?$filter=principalId eq '{ユーザーのObjectId}'
ポイントは「ObjectId(GUID)で指定する」ことです。UPN やメール アドレスを入れても一致しないため、結果が空になりやすいです(空配列は正常応答なので、エラーと誤認しがちです)。
前提条件を深掘り:なぜ 403/404 に見えるのか
ここからは、アプリケーション権限で呼ぶときに詰まりやすい 4 つの前提条件を、実務での見落としポイント付きで整理します。
管理者同意(admin consent)が「付与済み」になっている
アプリケーション権限は、追加しただけでは有効化されません。テナント管理者による管理者同意(Grant admin consent)が完了して初めて、クライアント資格情報フローでその権限がトークンに載ります。
- アプリ登録(App registration)→「API のアクセス許可」
- Microsoft Graph → アプリケーションのアクセス許可 に
PrivilegedAssignmentSchedule.Read.AzureADGroupを追加 - 画面上部の「管理者の同意を付与」などで、状態が同意済みになることを確認
よくある落とし穴は「権限を追加した後に、トークンを取り直していない」ことです。クライアント資格情報フローのトークンはキャッシュされることがあるため、権限変更後は必ず新しいトークンで再試験します。
トークンが “roles” クレームを持っている(app-only の証拠)
委任権限(delegated)では scp(スコープ)に権限が入るのに対し、アプリケーション権限(app-only)では roles に権限(アプリ ロール)が入ります。見た目が似ていても、トークンの種類が違うと Graph 側の判定も変わります。
確認方法はシンプルで、取得したアクセストークンを JWT デコーダー(例:jwt.ms)で開き、次の点を見ます。
rolesにPrivilegedAssignmentSchedule.Read.AzureADGroupが含まれているscpだけが入っている場合は「委任トークン」なので、同じ結果にはなりません
「クライアント資格情報フローで取っているはずなのに roles が無い」という場合、典型的には次のどちらかです。
- scope に
https://graph.microsoft.com/.defaultを指定していない(別リソースのトークンになっている) - 管理者同意が完了しておらず、Graph のアプリ ロールが割り当てられていない
対象グループが PIM for Groups の管理対象になっている(オンボード済み)
PIM for Groups は、すべてのグループが自動的に「PIM 管理対象」になっているわけではありません。PIM で管理する対象として有効化(オンボード)されていないと、API で「PIM の割り当て」を探しても見つからず、結果が返らない/404 になるケースがあります。
ポータル側では、一般に次の導線で「Discover groups」から管理対象に取り込む操作を行います。
- Microsoft Entra admin center → ID Governance → Privileged Identity Management → Groups
- Discover groups で対象グループを選び、Manage groups を実行
また、API 観点では「明示的なオンボード API」があるわけではなく、割り当て作成やポリシー更新などの操作をきっかけに自動オンボードされます。つまり、一覧系 API を叩く前に、対象グループが “PIM で管理される状態” に入っているかが重要です。
「現在アクティブな割り当て」が本当に存在している
assignmentScheduleInstances は “アクティブな割り当てのインスタンス” を返します。対象ユーザーがそのグループに対して PIM のアクティブ割り当てを持っていない場合、応答は 200 OK でも value が空になります。
- 「空配列=エラー」ではなく、「今はアクティブが無い」ことを表す正常応答
- Eligible(資格)だけで、まだ Activate していないユーザーはここに出ないことがある
まずはポータルの PIM(Groups)で Active assignments / Eligible assignments を見て、「アクティブがある前提」が正しいかを確認すると、切り分けが一気に楽になります。
実装例:クライアント資格情報フローでトークン取得→API 呼び出し
ここでは REST だけで再現できる、最小構成の流れを載せます。Graph Explorer は委任トークンになりやすいため、アプリケーション権限の検証には Postman や cURL を使うのが確実です。
アクセストークンを取得する(client credentials)
POST https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
client_id={clientId}
&client_secret={clientSecret}
&grant_type=client_credentials
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
取得した access_token をデコードし、roles に必要な権限が入っていることを確認します。
ユーザーのアクティブ割り当てを取得する(principalId フィルター)
GET https://graph.microsoft.com/v1.0/identityGovernance/privilegedAccess/group/assignmentScheduleInstances?$filter=principalId eq '{userObjectId}'
Authorization: Bearer {access_token}
特定グループのアクティブ割り当てを取得する(groupId フィルター)
GET https://graph.microsoft.com/v1.0/identityGovernance/privilegedAccess/group/assignmentScheduleInstances?$filter=groupId eq '{groupObjectId}'
Authorization: Bearer {access_token}
レスポンスには、accessId(member/owner)や assignmentType(assigned/activated)などが含まれ、アクティブ割り当ての状態把握に使えます。
レスポンス項目の読み方:何が分かるのか
assignmentScheduleInstances の 1 レコードは「いま有効な割り当て」を表すインスタンスです。特に現場でよく見るのは次のプロパティです。
| プロパティ | 意味 | 運用での使いどころ |
|---|---|---|
principalId | 割り当て対象のユーザー(または principal)の ObjectId | 誰が有効な権限を持っているかの突合 |
groupId | 対象グループの ObjectId | どのグループに対する割り当てか |
accessId | member / owner など、付与される関係 | 「メンバー」か「所有者」かの判定 |
assignmentType | assigned(直接割り当て)/ activated(資格の活性化) | “常時付与” か “JIT” かを分析 |
startDateTime / endDateTime | 有効期間 | いつからいつまで有効か。期限切れの検知 |
たとえば「activated」が多いグループは JIT 運用が徹底できている、などの監査観点の指標にもなります。
トラブルシュート:403 / 404 / 空配列 を最短で切り分ける
エラーや空結果のパターンは似ていますが、原因はだいたい決まっています。まずは下の表で “当たり” を付け、確認作業を一直線にします。
| 症状 | ありがちな原因 | 確認ポイント | 対処 |
|---|---|---|---|
| 401 Unauthorized | トークンが無効 / aud が違う / 期限切れ | Authorization ヘッダー、トークン有効期限、aud | トークンを取り直し、Graph 用(graph.microsoft.com)であることを確認 |
| 403 Forbidden | 管理者同意が未完了、または roles に権限が無い | アプリ登録の同意状態、JWT の roles | 管理者同意→新しいトークンで再試験 |
| 404 Not Found | エンドポイントの打ち間違い / グループが PIM 管理対象でない等 | URL が /identityGovernance/privilegedAccess/group になっているか | 正しい URL に修正。必要ならグループを PIM 管理対象へ |
| 200 OK だが value が空 | 割り当てが無い / フィルターが一致していない | principalId/groupId が GUID か、アクティブ割り当てがあるか | ObjectId を正しく指定。ポータルで Active assignments を確認 |
| 400 Bad Request | $filter が無い/プロパティが誤り | PIM グループ側は $filter 必須 | groupId または principalId で eq フィルターを付ける |
オンボード状態の確認と「管理対象にする」手順
「PIM グループとして管理されているか」は、API の前段で必ず確認したいポイントです。運用で迷わないために、ポータルと API の両面での考え方をまとめます。
ポータルで確認する(最も早い)
- ID Governance → Privileged Identity Management → Groups に対象グループが表示されるか
- 表示されない場合は Discover groups から検索し、Manage groups を実行する
- Dynamic groups やオンプレ同期グループは PIM for Groups の管理対象にできない点も要注意
API での考え方:明示的なオンボード API は無く、操作がトリガーになる
Graph の PIM for Groups では、割り当て作成やポリシー更新などの操作により、必要に応じて自動オンボードが行われます。つまり「一覧を取る前に、少なくとも一度 PIM の管理対象として扱われる状態に入っている」ことが重要です。
手元の検証で「一覧が返らない」場合は、次のような “PIM 側の操作が通るか” を先に確認すると、オンボード未完了の切り分けになります。
- assignmentSchedules(スケジュール)を一覧できるか
- policy(ルール)を参照できるか
- (検証環境なら)テスト用の割り当てスケジュールを 1 件作る
実務で効く小ワザ:原因特定を速くするチェックリスト
最後に、現場で「次の一手」を迷わないためのチェックリストを載せます。作業者が変わっても同じ基準で切り分けできるようになります。
| チェック項目 | 推奨アクション | 判断基準 |
|---|---|---|
| API のアクセス許可が admin consent 済み | ポータルで同意状態を確認し、同意後に新トークンで再実行 | 「同意済み」になっている |
| トークンに roles が入っている | JWT をデコードして roles を確認 | PrivilegedAssignmentSchedule.Read.AzureADGroup が含まれる |
| 対象グループが PIM 管理対象 | Groups 画面に表示されるか、Discover groups から管理対象にする | PIM の Groups に出てくる |
| フィルター条件が正しい | principalId / groupId を GUID で指定 | 空配列か、期待通りの value が返る |
| 期待しているのが「アクティブ」か「資格」か | Eligible と Active を混同しない | “今有効” を取りたいなら scheduleInstances が適切 |
よくある質問
委任権限だと動くのに、アプリ権限だと動かないのはなぜ?
委任権限は「ユーザーの権限+アプリのスコープ」で動き、トークンも scp 中心になります。一方アプリ権限は、管理者がアプリそのものに権限を付与し、トークンは roles で評価されます。どちらのトークンで試しているかが混ざると、同じ API でも結果が変わります。
403 が出るとき、最初に見るべき 1 点は?
まずは「管理者同意が付与済みか」と「トークンの roles に権限が入っているか」です。ここが揃っていない限り、他の切り分けをしても戻ってきます。
200 OK で空配列なのはバグ?
多くの場合は仕様どおりです。アクティブ割り当てが無い、フィルターが一致していない、対象が PIM 管理対象になっていない、のいずれかで起きます。まずはポータルで Active assignments を見て、前提を固めてから API 側を追うと早いです。
まとめ:アプリ権限で “動く形” を作るための最短ルート
- PIM グループの assignmentScheduleInstances は、アプリケーション権限でも利用できる。
- ただし admin consent、トークンの roles クレーム、グループの PIM 管理対象化(オンボード)、そして アクティブ割り当ての存在 が揃わないと「動かない」に見える。
- さらに PIM グループ側は $filter が必須 なので、groupId/principalId を GUID で指定する。
この 4 点をチェックリスト化しておくと、403/404/空配列の迷子から抜け出しやすくなります。

コメント