SharePointVault ~/gotchas/graph ⌕ Search 404 pages, error messages, scripts…Ctrl K ★ Star
M↓ README.mdM↓ teams-channel-messages-need-a-teams-license.md
sharepoint-vault›gotchas›graph›teams-channel-messages-need-a-teams-license.mdhistoryedit on GitHub
● GOTCHAgraph· 3 min read

Reading Teams channel messages needs a Teams license on the reader

applies to: Microsoft Graph v1.0 (/teams/{id}/channels/{id}/messages, /teams/{id}/allChannels, /groups/{id}/members/$ref), delegated permissionsreviewed: 2026-10-31#graph#microsoft-teams#channels#licensing#delegated-permissions#403

With delegated ChannelMessage.Read.All consented, an account without a Teams license gets 403 on every channel's messages — including teams it is a member of. The permission and the membership are not enough; the signed-in reader needs a license that includes Teams. Listing channels is different: GET /teams/{id}/allChannels returned the channels of a team the (Global Admin) account was not a member of.

S delegovaným ChannelMessage.Read.All dostane účet bez licence Teams u zpráv každého kanálu 403 – i v týmech, kde je členem. Oprávnění ani členství nestačí; přihlášený čtenář potřebuje licenci, která obsahuje Teams. Výpis kanálů se chová jinak: GET /teams/{id}/allChannels vrátil kanály i týmu, kde účet (globální správce) členem nebyl.

Symptom

GET https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/messages?$top=5
Authorization: Bearer <delegated token, scp contains ChannelMessage.Read.All>

HTTP/1.1 403 Forbidden
{ "error": { "code": "Forbidden",
  "message": "Failed to get license information for the user. Ensure user has a valid ..." } }

Measured on a live tenant with a Global Administrator account that has no Teams license: the same 403 in all six teams, five of which the account was a member of.

What still works

GET https://graph.microsoft.com/v1.0/teams/{team-id}/allChannels?$select=id,displayName,membershipType
HTTP/1.1 200 OK

It returned the channels of a team the account was not a member of. Microsoft documents this as "admin permissions" for Teams service admins on the channel list APIs. A private channel the admin is not a member of is listed too (name and membershipType), in both allChannels and channels; its /members returns 403.

A licensed member gets a vague 403 on private channels

A second measurement with a licensed account that is a member of every team: all standard channels returned 200 OK, but a private channel the account had left returned:

HTTP/1.1 403 Forbidden
{ "error": { "code": "UnknownError", "message": "" } }

Nothing in the error says "not a member". Interpret a 403 on a private or shared channel by the channel's membershipType, not by the error text. Not measured: a licensed account that is not a member of the team at all.

What to do

  • If a tool reads channel messages on behalf of the signed-in user, run it under an account with a Teams license, and tell the user exactly that when the 403 says "license information" — do not show it as "access denied" or "not a member".
  • Treat a 403 on a private or shared channel as "not a member of the channel" and say so; only the channel owner (or ChannelMember.ReadWrite.All) can add the account.
  • To add a check account to teams, POST /groups/{id}/members/$ref works with GroupMember.ReadWrite.All; /teams/{id}/members needs TeamMember.ReadWriteNonOwnerRole.All instead.
  • Build the "not read" list from allChannels: it works without membership, so you can report every channel you could not read, with a reason.
  • Do not plan on "one E5 license" to get Purview DLP for Teams across the tenant: Microsoft requires a license for every user who benefits — for channel messages, the team's owners and members (Microsoft Purview service description, "Which users need a license?").

Sources

Was this helpful?ask or add your experience on GitHub →
Saved you an hour? A star on GitHub helps other SharePoint people find the vault.★ Star on GitHub
last reviewed: 2026-10-31last updated: 2026-10-31historyedit on GitHubview source