Permission Flow
A permission flow maps who can do what, and — the half that gets skipped — what everyone else sees when they can't. Three distinct systems get called "permissions"; a product often has all three:
- Role-based access: admin / owner / editor / viewer / guest.
- Account-tier access: free / trial / paid / enterprise — the same UI gated by billing instead of trust.
- Device permissions: camera, mic, location, notifications, contacts — granted by the OS, revocable outside your product.
When to use one
Any multi-user product, plans/tiers, or device capabilities. Draw it before wireframes: every cell of the permission matrix is a screen variant someone must design, and undesigned cells ship as silent 403s and mystery-disabled buttons.
What it answers
- For each role × action pair: allowed or not?
- For each "not": what does that user SEE, and what's their route to getting the capability (request, upgrade, ask the owner) or a dignified alternative?
- For device permissions: when do we ask, what happens on "no," and how does the user recover after a denial?
The permission matrix — roles × actions
List real actions (not features) down the side, roles across the top. Then make the design decision per cell — the matrix below shows the decision vocabulary in use:
| Action | Admin | Owner | Editor | Viewer | Guest |
|---|---|---|---|---|---|
| View project | Allow | Allow | Allow | Allow | Request access |
| Edit content | Allow | Allow | Allow | Disable + "Viewers can't edit — request edit access" | Hide |
| Invite members | Allow | Allow | Disable + "Ask an admin" | Hide | Hide |
| Export data | Allow | Allow | Upgrade prompt (paid tier) | Hide | Hide |
| Delete project | Allow (any) | Allow (own) | Hide | Hide | Hide |
| Billing settings | Allow | Allow | Hide | Hide | Hide |
The four verbs for a blocked cell, and when each fits:
- Hide — when the capability is irrelevant or its existence is sensitive (billing from viewers). Cost: undiscoverable; nobody ever requests what they can't see.
- Disable with explanation — when the user should know it exists and why it's off, with the route named ("request access," "ask an admin"). Never a bare grayed-out button — an unexplained disable is a support ticket.
- Upgrade prompt — for tier gates: show the capability, state the tier, make the value case. This is marketing surface; overuse reads as a nag wall (check Persuasion, Ethics & Dark Patterns).
- Request access — for role gates: a one-tap request that notifies whoever can grant it, tells the requester it's pending, and closes the loop on grant/deny. The request itself is a multi-user flow (Multi-User Flow).
Convention: hide what's irrelevant, disable-and-explain what's aspirational, and never let the user compose work they can't submit — check permissions before the effort, not at the save button.
Device-permission flows: prime → ask in context → handle denial
OS permission dialogs are one-shot and system-owned, so the flow around them is your only design surface (platform details: Mobile App Design; prompt patterns: Notifications & Communication and Privacy & Security UX):
Feature needs camera
├─ Not yet asked ──▶ Prime in your UI ("Scanning needs the camera —
│ enable it?") at the moment of use, never at launch
│ ├─ user says yes ──▶ OS dialog ──▶ granted ──▶ feature
│ │ └─▶ denied ──▶ denial state
│ └─ user says no ──▶ dismiss quietly; re-offer only at next
│ natural use — priming "no" costs nothing, unlike an
│ OS-level "no" (Apple HIG / Android guidance: ask in
│ context, with the reason)
└─ Previously denied ──▶ denial state: explain what's unavailable,
offer the SETTINGS RECOVERY PATH ("Enable camera in
Settings ▸ Privacy" + direct settings link where the OS
allows) + a fallback (type the code instead of scanning)
The denial state is permanent UI, not an edge case: users revoke permissions in OS settings months later; degrade to something useful, never a blank screen demanding the camera.
Example — role gate as a decision flow
User opens Team Settings
├─ admin? ──▶ full Edit Team Settings
├─ member (editor/viewer)? ──▶ View Only + "Only admins can edit —
│ request admin access" ──▶ request sent ──▶ pending badge
│ ├─ granted ──▶ notify + unlock (return them to this page)
│ └─ denied/expired ──▶ notify with reason or "ask <owner>"
│ — never silent limbo
└─ guest? ──▶ Request Access gate (page existence acknowledged,
contents hidden) ──▶ same request loop as above
Failure branches to note: the request loop closes in all outcomes (granted, denied, expired) — an unanswered access request is the permission flow's most common dead end. Also design the demotion branch: what happens to an editor's draft when they're downgraded mid-edit (preserve the work, block the submit, explain).
Common mistakes
- Designing only the admin's view; every other role inherits broken layouts full of hidden gaps.
- Bare disabled buttons with no reason and no route.
- Asking for all device permissions at first launch (documented denial driver — see Mobile App Design).
- No settings-recovery path after an OS-level denial.
- Access requests that vanish into nowhere — no notification to the granter, no status for the requester.
- Checking permissions only in the UI; the API allows what the button hid (a security bug wearing a UX costume).
Checklist
- Matrix exists: every action × every role (+ every tier), every cell assigned hide / disable+explain / upgrade / request.
- Each role's version of each screen is designed, not inferred.
- Every disable states its reason and its route.
- Request-access loop closes on grant AND deny, with notifications both ways (Multi-User Flow).
- Device permissions: primed in context, denial state designed, settings recovery path + fallback provided.
- Mid-session changes handled: revocation, demotion, expiry, and logout preserve in-progress work.
- Permission-denied appears as a state in the component's State Flow; enforcement exists server-side, not just in the UI.
Sources
- Apple Human Interface Guidelines — requesting permission in context, with purpose strings (developer.apple.com/design).
- Android developer guidance — runtime permissions: request in context, handle denial gracefully (developer.android.com/training/permissions).
- Platform specifics and prompt-timing evidence: Mobile App Design; Privacy & Security UX; Notifications & Communication (this library).
- Role/tier matrix practice is industry convention (access-control matrices from computer security, adapted to UI); labeled as convention, not a cited standard.