#permissions 64 articles
"0 sent" hides whether anyone was even asked — boolean mail wrappers conflate refusal with an empty audience gotchas / graph The recipient side of the same trap: a denied group read becomes an empty audience, an empty audience becomes a benign false, and an approval queue notifies nobody "File is missing" and "I cannot read the file" collapse into the same null — and the empty state then lies gotchas / rest-api A T | null helper folds 404, 403, 500 and network failure into one null, and the friendly empty state then lies to the one user who has overdue work; return {ok, status, data} and let only 404 (on every candidate path)… "The requested permission isn't valid" in API access — the API registration doesn't exist yet gotchas / spfx API access resolves resource to a service principal, so the app registration must exist before the .sppkg is uploaded "User:… dont have any permissions" from the audit query API rejects the USER, not the app gotchas / graph Consent vs. Exchange audit role; Global Admin usually inherits it, so compare accounts /_api/hubsites is trimmed per user — a lookup that walks the hubs finds your app for the page editor and not for the reader gotchas / rest-api GET /_api/hubsites returned 2 hubs to an admin and 1 to an ordinary user who had Full Control on the missing hub's site, so client code that discovers something by walking the hub list works for the editor and silently… /_api/HubSites returns an empty list (HTTP 200) when the caller cannot see the hub sites gotchas / rest-api The hub list is security-trimmed, so an account that cannot read the hub sites gets value: [] with HTTP 200; "this site has no hub" and "no inherited owner" must never be derived from it — read IsHubSite/HubSiteId from… getfolderbyserverrelativeurl returns 200 for a folder that does not exist gotchas / rest-api It answers HTTP 200 with {"Exists": false} (and ListItemAllFields 200 with {"odata.null": true}), so a check on response.ok skips creating the folder and the next call 404s inside breakroleinheritance; measure the… A "grant it for me" button cannot work in a web part — not even for a Global Administrator gotchas / spfx A delegated call gets the intersection of the user's rights and the app's grants, so the admin at the keyboard adds nothing; writing the grant would take at least DelegatedPermissionGrant.ReadWrite.All approved for the… A comma in a Graph permissions table can mean AND — searching Teams messages needs two scopes gotchas / graph Searching chatMessage needs Chat.Read and ChannelMessage.Read.All; the 403 spells it out, the table does not (+ webUrl vs webLink from the same endpoint) A count over a ReadSecurity 2 list is only the reader's share — and the bit that says "sees everything" is Manage Lists alone gotchas / permissions Item-level read security filters rows silently, so a client-side count or ranking is the reader's own rows; show it only with ReadSecurity = 1 or Manage Lists in the reader's mask, and don't also demand Override List… A deleted site and a site you cannot see are two different answers — read the status, not ok gotchas / rest-api _api/web on a non-existent site collection answers 404 (measured, no redirect), so if (!r.ok) return unknown makes a dead row in your own site inventory look like a site you merely lack permission on; keep r.status… A drop box for sensitive files — a document library can't do it, a list with ReadSecurity 2 and attachments can (measured, including the direct attachment URL) gotchas / permissions Giving someone write access to a protected library folder also lets them read every file in it; a list with ReadSecurity = 2, Contribute for the senders and Edit for the reviewers lets people send files they alone can… A folder created with folders/AddUsingPath in a generic list has no list item — breaking its permissions returns 404 gotchas / rest-api In a custom list (BaseTemplate 100) web/folders/AddUsingPath creates a 'naked' folder: ListItemAllFields is odata.null (@odata.null under SPFx's OData v4) and breakroleinheritance is 404. Create list folders with… A Graph scope your SPFx solution never asked for may already work — grants are tenant-wide gotchas / spfx webApiPermissionRequests is a request, not a grant; an approval lands on one tenant-wide principal, so a scope another solution had approved already works in yours (and may be missing at the customer) A library your app provisions inherits the web's write permissions — and that is how an AI grounding source gets poisoned gotchas / security Any member can upload over REST and poison an AI grounded on that library; WriteSecurity: 4 does not fix it (Edit includes Manage Lists and bypasses item-level settings) — only unique permissions on the library do A list with WriteSecurity 4 ignores Contribute — only ManageLists gets through gotchas / permissions Only ManageLists (Design/Edit/Full Control) overrides the item-level write block, so "break inheritance + give the group Contribute" grants nothing; resolve the role by RoleTypeKind, not by its localised name A mail-permission probe that can't tell "no mailbox" from "no consent" lies to admins gotchas / graph /me/messages 404 MailboxNotEnabled* on mailbox-less accounts ≠ missing consent; three verdicts, and never cache a negative probe result A permission check that only asks "who has too much?" passes on an empty ACL gotchas / permissions "no principal outside the allow-list can write" is also satisfied when nobody can write at all; assert the opposite direction with a non-zero writer count, and read the principals strictly so a transient 429 cannot… A provisioned list with ReadSecurity=2 looks perfect to an admin and empty to everyone else gotchas / lists ReadSecurity=2 looks perfect to an admin and empty to everyone else; WriteSecurity=2 breaks collaborative edits only A provisioning step gated on success runs forever for every non-admin gotchas / spfx A startup step needing ManageLists writes no marker for ordinary members, so the whole batch replays on every page load; the marker needs two states A read-only mode that wraps SPHttpClient still sends e-mail — Graph is a second channel gotchas / spfx An SPFx app writes through two clients; wrapping SPHttpClient leaves mail, calendar and Planner wide open A setup marker that measures only part of the step freezes a half-provisioned site forever gotchas / spfx The success flag measured the id lookups, not the addroleassignment POST, so a 403 froze a site with groups that carry no permission level at all A SharePoint group created by code hides its own membership — and Full Control does not get you in gotchas / security sitegroups POST defaults to OnlyAllowMembersViewMembership: true, so only a member or the account that ran provisioning can read the members; Full Control does not help and identical permission masks prove it A status code measures where the request stopped first, not what the user may do gotchas / permissions A probe that writes with a deliberately stale IF-MATCH and reads permissions off 403 vs 412 measures which gate the request hit first: SharePoint evaluates the etag BEFORE authorisation, so 412 comes back even where… A throttled permission probe must not downgrade — and cache — the role gotchas / rest-api A 429/403 on currentuser/groups resolves to the lowest role; cache it and the user is stuck read-only for the TTL; only persist a confirmed (200) result A user with Read on one page only is denied at the site root URL — link to the page, not the site gotchas / permissions When a principal has Read on a single page in Site Pages and only Limited Access on the site, opening the site URL ends on AccessDenied.aspx even though the page itself opens fine — so a link that falls back to the… Actions must go before the alias query string, not after the URL gotchas / rest-api Appending /breakroleinheritance(...) to a GetList(@u)?@u=... URL buries the action inside the parameter — splice it in before the ? An "add what's missing" permission sync turns every change of owner into a leak — the previous owner keeps access gotchas / permissions Idempotent grant-only re-sync is safe at item creation but not when an item moves to another customer or team — the old group stays on the item; remove by principal Id, keep a protected set, and verify with a second… An Entra group inside a SharePoint group is invisible to every membership check SharePoint offers gotchas / security SharePoint accepts an Entra group as a member of a site group, then never expands it: currentuser/groups is direct-only and sitegroups/{id}/users returns the group, not its people — resolve with Graph checkMemberGroups… An evidence record whose "who" is written by the browser proves nothing — compare it with the server-stamped Author, and compare on the sign-in name too gotchas / lists Append-only lists let any contributor add a row with someone else's name in a text column; Author is stamped by SharePoint. Compare the two — but against Author/Name (the sign-in claim) as well, or every user whose… ApplicationAccessPolicy won't scope to a shared mailbox — use a mail-enabled security group gotchas / graph "not a security principal"; scope app-only Mail.Send to a mail-enabled security group Approving Microsoft Graph permissions for SPFx needs a Global Administrator — Application Administrator is not enough gotchas / permissions API access requests for Microsoft Graph need Global Administrator (Application Administrator only covers third-party APIs), and admin consent for Graph application permissions such as Sites.Selected is explicitly… az CLI can't grant Sites.Selected — the scope is blocked by AADSTS65002 gotchas / graph sites/{id}/permissions needs Sites.FullControl.All; the CLI client can't request it (AADSTS65002), use the Graph PowerShell SDK Breaking inheritance copies foreign Edit grants — and Edit defeats item-level security gotchas / security Another app's groups arrive with Edit, which carries ManageLists and bypasses item-level security; break without copying and prune the ACL — but only on a genuinely polluted scope, because copyRoleAssignments=false… Breaking inheritance without copying keeps only YOU — and the re-grant forgets custom groups gotchas / permissions copyRoleAssignments=false leaves exactly one role assignment (the caller), so re-granting Owners/Members/Visitors drops every direct grant and custom group; and an account that loses a configuration read can end up… Check another user's effective permissions (without their password) snippets / rest Verify what a normal user can actually reach — from your own session, no test account; mind Open = Low bit 16 Checking someone else's group membership — ask the group, not the user gotchas / graph /me/checkMemberGroups only answers for you; ask the GROUP for its transitive members instead, and never turn "could not determine" into "not a member" Contribute on the web lets a role edit and delete the pages of the site — including the page your app lives on gotchas / permissions Modern pages are items in the Site Pages library, which inherits from the web, so a group you give Contribute on the web "so it can write list items" can also edit and delete every page; withholding Manage Lists does… Counting a site's audience from its associated groups silently misses nested groups gotchas / permissions Owners/Members/Visitors often contain Everyone except external users or the Microsoft 365 group claim (PrincipalType 4); keeping only PrincipalType 1 rows turns a whole company into one or two people – treat any nested… Fewer sites and sudden 403s usually mean a different account, not a tenant outage gotchas / security A tenant-wide snippet run from a second browser window executes as whoever is signed in there; print currentuser and the visible-site count before you blame the tenant FirstUniqueAncestorSecurableObject has no type in odata=nometadata — tell web, list and item apart by the shape of the answer gotchas / permissions The endpoint returns a web, a list or a list item depending on where inheritance breaks, and with odata=nometadata nothing names the type; classify by properties (FileSystemObjectType = item, BaseTemplate = list… GetObjectSharingInformation — GET always 405, CreatedBy always null, and other measured facts gotchas / rest-api GET is 405 every time (stop retrying it: 2.7× slower), CreatedBy is always null, $expand is dead weight GetUserEffectivePermissions ignores the user's Entra security groups — and Full Control's effective mask is not the role's mask gotchas / permissions Asked on behalf of another user, GetUserEffectivePermissions counts Microsoft 365 group membership but not Entra security group membership — directly assigned or nested in a SharePoint group, still after 40 s — so it… getUserEffectivePermissions returns a 64-bit mask — decode it wrong by one bit and every user looks locked out gotchas / security ViewListItems is bit 0, Low/High are decimal strings; decode off by one and every ordinary member looks locked out. Sanity-check the decoder against a site admin AND a known Read user Graph /me/sendMail — From is always the signed-in user gotchas / graph Delegated Mail.Send can't impersonate; configure Reply-To instead Guests cannot join a Teams shared channel — only people from another Microsoft 365 organisation can gotchas / permissions Shared channels admit external people only through B2B direct connect between two Entra tenants; a guest account cannot be added, so a partner without their own Microsoft 365 needs a different design HasUniqueRoleAssignments proves the break, not the hardening — and a half-done break is worse than inheritance gotchas / permissions The flag is true after the break alone, so verifying on it reports "hardened" over a list whose trim never ran; with the safe copy=true form that state is worse than inheritance. Read roleassignments and measure… Hiding a field in an SPFx web part is not a permission gotchas / security Role-based UI field hiding is cosmetic; Read on the list = REST/Export/other web parts see it; confidentiality needs a separate list, item perms, or a server tier — plus the two traps the separate list creates: a… Item-level edit rights cover every field – don't trust status, approver or link fields the user can write gotchas / permissions Unique permissions on an item don't separate fields: whoever may edit it can set Status, Approver or a lookup Id via REST – derive trust from admin-only data and version history Limited Access cannot be granted — the API returns 200 and does nothing gotchas / permissions RoleTypeKind: 1 is derived, not assignable: SharePoint maintains it so people can traverse to a child with unique permissions, and an explicit addroleassignment returns 200 while doing nothing. Strip it from EVERY… Locking down a no-script site from code: web NoCrawl is denied even to a site collection admin, and turning off access requests returns 200 and changes nothing gotchas / security On a modern site with custom scripts disabled, NoCrawl on the WEB returns 403 via REST and CSOM even for a site collection admin, and SetUseAccessRequestDefaultAndUpdate(false) returns 200 without effect; both work… Manage Lists lets you read other people's items on a WriteSecurity 2 list, but not edit them — that takes Override List Behaviors gotchas / permissions On a list with item-level write security, the Edit role (Manage Lists) still gets 403 when it updates an item someone else created; only a role with Override List Behaviors (CancelCheckout, Low 0x100) gets through, so… Narrowing a principal to Read — "already reads" checked before stripping write leaves it with nothing gotchas / permissions Edit and Contribute contain the View bit, so a "does it already read?" check passes, Read is never added, and the step that removes the write binding then removes the only binding that carried read access — the… PATCH /me — directory and profile fields cannot share one request gotchas / graph Mixed field groups fail whole; two PATCHes, profile best-effort PermissionKind is 1-based — decoding BasePermissions with 1 << kind invents a security finding gotchas / permissions The flag for kind k is 1 << (k - 1), so 1 << k invents a security finding: Contribute appears to hold ManageLists (it holds ViewFormPages). Calibrate any decoder against a known level first, and note the tell — a… Provisioning folder trees at scale in SharePoint Online guides What creating 86 folders and breaking inheritance really costs (no throttling), the alias-parameter syntax, reading a whole tree with one item query (two calls) instead of ninety, and copyRoleAssignments=false silently… Purview audit query API — a query for a service you have no scope for still "succeeds" with 0 records gotchas / graph With only AuditLogsQuery-SharePoint.Read.All, Exchange and Entra queries return 201 → succeeded → 0 records; an unfiltered query returns only SharePoint records Restoring inheritance is a one-way door — snapshot the unique assignments first gotchas / permissions resetroleinheritance throws away every unique role assignment and SharePoint keeps no copy, so an "undo" is only possible if the code saved the assignments BEFORE the call; re-breaking with copyRoleAssignments=true… Tenant-wide enumeration in Graph is app-only — check Delegated vs Application before you build gotchas / graph getAllSites rejects delegated tokens; check the Permissions table first The crawl log DOES exist in SharePoint Online — it just isn't where you look for it gotchas / search Reachable only through CSOM DocumentCrawlLog via /_vti_bin/client.svc/ProcessQuery, gated by a separate Crawl Log Permissions grant that no admin role implies; returns ~52 columns incl. per-pass crawl timestamps… The tenant root site is not necessarily readable by everyone gotchas / permissions Measured: unique permissions, no Everyone except external users, an ordinary employee's mask High=0, Low=0; don't anchor a must-work-for-everyone mechanism there, measure with getusereffectivepermissions There is no sitegroups/removebyname — delete a group by Id gotchas / rest-api GroupCollection has GetByName but only RemoveById; resolve the Id first, then delete; verify with getbyname → 404 Version-gated provisioning silently drops the settings only an admin could write gotchas / lists A settings PATCH needs Manage Lists; the first member to open the app after an upgrade burns the one attempt and the version is stored anyway View counts and ratings written by readers cannot live in a list only editors may write gotchas / lists Views and ratings are written by the reader, so on a WriteSecurity: 4 content list every click is a swallowed 403 while the UI says thanks