Completing user access reviews

A user access review is a process where you audit what your users have access to in your environment. You review access and remove what's no longer needed.

Last updated


What is a user access review?

A user access review is when you audit what your users have access to in your environment. You consolidate information about who has access to what across your apps and infrastructure, decide whether each user still needs that access, and remove what’s no longer required. This is a process meant to be run regularly.

Often, the motivation to start running access reviews is compliance. In SOC 2, access reviews fall under the requirements for managing logical access (CC6.1), reviewing access (CC6.2), and assigning role-based access (CC6.3). In ISO 27001:2022, Annex A 5.18 covers both provisioning and removing access, as well as regularly reviewing it. Access reviews are often completed quarterly, though neither of these standards specifies a required cadence.

The goal of an access review is to find access that isn’t correct and update it. You shouldn’t expect to just confirm everything is fine, but rather find access that’s no longer required based on job roles, or for a user that should have been offboarded. And that’s normal: entitlements grow organically over time, from one-off requests, permissions copied between users, or overprovisioning to unblock someone in a hurry — and nobody goes back to clean up. Finding forgotten access is the expectation, and a review that turns up nothing could come off as though you didn’t really look.

Completing access reviews for security vs for compliance

Access reviews show up in SOC 2 as a control, so most people first encounter them as a compliance task that they need to complete for an audit — that's why so much advice about access reviews is about producing evidence, rather than removing access. But although an audit is often the motivation (and sets the deadline) for completing an access review, there’s value in the review beyond a compliance checkbox.

The compliance question you need to answer for your auditor is whether you performed a review of access, on the schedule you stated, with evidence you can hand over. Conversely, from a security point of view, the goal of an access review is to make sure you’re following the principle of least privilege, so that no one has access they shouldn’t. They’re not at odds with each other, but completing the process for compliance doesn’t automatically mean you get the benefits for security. Compliance sets a minimum bar for user access reviews. But if you review your access with the goal of getting to least privilege, what you need for compliance will fall out of that process anyways.

Most remediation discovered in access reviews will be for movers, not leavers. When someone leaves, this sets off a process, however imperfect — there's a last day with a checklist. But someone moving from support to engineering doesn’t necessarily get noticed the same way. They're still here, still working, and now they hold both sets of access. If there’s no process watching for that, the access review is what catches it.

How to run a user access review

  1. List every app you use. Your app inventory is the scope of the review: every app, environment, and internal tool your users can log into, including the shadow IT that isn't connected to your identity provider. The list of apps you use is longer than you expect, and building this list is most of the work the first time you complete an access review.
  2. Get your list of people. Pull a current roster from your HR system: names, work emails, start and end dates, employment type, and team. If you have a separate system for contractors, pull that list too.
  3. Get access information from each app. Export the list of users and their access directly from each app's own admin console or API, not from your identity provider, since they may be out of sync. You want accounts, roles, and permission levels, plus whether each account is federated (comes from your identity provider) or is local (local username and password). A screenshot is fine. If you can get it, additional information like whether the account uses MFA or has signed in recently is also useful.
  4. Create a centralized view of access. Put all of this information in one place, so that you can review it all together. For your first review, it doesn’t need to be any more complicated than a spreadsheet where each row is one entitlement: one user, one app, one role. That row is the unit you review, decide on, and produce evidence for.
  5. Focus on the most critical apps first. You are going to have a lot of access to review. To make sure you focus on what’s important, identify what apps are critical (e.g., production systems) or store sensitive data (e.g., customer data). Review these first, before you review anything else, or you'll end up spending the time when you’re freshest on something less important.
  6. Review every entitlement. Review all of the access your users have. It’s easiest to group and review these either by app (who should have access to the CRM?) or by user (what does this contractor have access to?). When you hit an entitlement you’re unsure of, ask someone with more context, like whoever owns the app.
  7. Document a decision for every entitlement. Make a decision to approve, remove, or change access, with an explicit documented reason where the decision needs additional context.
  8. Remediate, then verify. You’re almost done, but you still need to complete every remediation action you’ve identified. Confirm you made the change directly in the app, and track this remediation with a closed ticket and updated evidence.

What should you include in an access review?

The best practice is to review everything in your environment, but to spend more time where it matters. Although it might be tempting to cut scope and only review a few critical apps, that's not recommended, since that's how you end up forgetting something critical. Your app inventory is what defines that scope, and it needs to be complete for your critical apps: production, customer data, and admin consoles. For the long tail, review what's on the list and keep adding to it as you find more.

Instead of changing the scope of coverage, vary the depth of your reviews:

  • Go deep for anything touching customer data, anything in production, and every admin or owner role in any app. Spend time reviewing each entitlement, and answering why this user has this access. Admin and owner roles are the smallest population and the biggest exposure, so they’re still worth your time in apps you might otherwise skim. Make sure to also include your production infrastructure and your product’s own admin console in scope.
  • Skim internal tools with sensitive-ish data. Review who has access to your code, HR systems, and financial reporting. Look over each app's access list for anyone you didn’t expect to see there.
  • Confirm access for the long tail of SaaS. Check that the app's user list matches people who still work at your company, and in relevant roles. It’s worth spending more time on apps that aren’t behind SSO, where you might not have a centralized list at all.

Who counts as a user in an access review?

If a user can log in to apps you use, they should be included in the review. You should review everyone who has access in your environment, whether or not they're on payroll: not only employees, but also contractors, interns, consultants, and partners.

Guests and external collaborators are often the ones who get forgotten, such as outside collaborators on a GitHub repo, external members in a Slack Connect channel, or anyone with guest access to Notion. This guest access isn’t usually granted through traditional provisioning processes and so often gets missed. And if you’re reviewing access for PCI, this is a requirement: Requirement 7.2.4 explicitly mentions reviewing third-party and vendor accounts at least every 6 months.

What’s less obvious is whether or not you should review service accounts, shared accounts, or other non-human identities. They aren't strictly what a user access review asks about, but including them isn't a bad idea. If you do review them, also take the time to define an explicit owner for each so that the reviews get easier next time.

Get the list of current access directly from an app, not your identity provider

When doing an access review, it feels reasonable to separate the reviews into SSO and non-SSO apps, and then pull access for the SSO apps from your identity provider. Unfortunately, you can’t rely on the access information in your identity provider, and you should pull the access list from each app directly.

Having SSO doesn't mean you know who has access. Your identity provider tells you who can authenticate to an application, but not what they can do once they’re in, or that it’s the only way that they can get in. You likely have apps in multiple states:

  • App behind SSO with provisioning. In this case, your identity provider knows the app exists and roughly who should be in it, and provisions users and groups to the app. It still doesn't reliably know in-app roles, and it doesn't know about accounts created outside of what it’s generated.
  • App behind SSO without provisioning. In this case, you’re using your identity provider to authenticate to the app, and nothing more. The app holds its own state on users and permissions, which drifts over time and doesn’t keep up to date with changes in the identity provider: you could offboard someone from your identity provider but leave their app account intact.
  • App isn’t behind SSO at all. In this case, your identity provider isn’t aware of the app at all — it’s “shadow IT”. Any changes you make to access need to be directly in the app.

If your identity provider explicitly assigns apps, like Okta does, then you should have an app catalog, with who was assigned what. It’s a great starting point, but it’s more of an inventory than a list of access — you might not know why or how they have that access, and you still don’t know what actual access users have in those applications. To know the actual in-app roles, you need Okta Identity Governance or another solution.

If your identity provider is configured to allow broad authentication, like Google usually is, you might not have that. Most companies who use Google as their identity provider have it set up so that users can sign into whatever they want — nothing has to be configured first, and there’s no explicit assignment. Google keeps track of OAuth grants, which show you which apps your users authorized, but that doesn’t mean someone is currently using the app; and again, users could have signed in in other ways.

Either way, what’s in your identity provider isn’t perfect, so diff what it thinks against what the apps report.

How often should you conduct access reviews?

The cadence that many auditors expect is quarterly access reviews. A reasonable goal is to review critical apps quarterly, and everything else annually. But what really matters here is what you’ve put in your policy, if you have one — its cadence overrides that, as your stated cadence is what you get held to. Running late against your own policy is a finding no matter how sensible the interval was. Undercommit and overdeliver.

The SOC 2 Trust Services Criteria don't specify a frequency at all. CC6.2 and CC6.3 require that access is authorized, reviewed, and removed when it's no longer needed, but leave the frequency up to you. ISO 27001:2022 Annex A 5.18 is the same: the requirement is a periodic review, but no interval is specified. Quarterly is the convention, not a strict requirement for SOC 2 and ISO 27001.

Some frameworks do provide strict requirements, though. PCI DSS v4.0.1, Requirement 7.2.4 requires that all user accounts and related access privileges, including third-party and vendor accounts, are reviewed at least once every six months. Application and system accounts are handled separately under 7.2.5.1. If more than one framework applies to you, then adopt the strictest controls.

How much a team moves matters too: if you frequently have role changes or reorganizations, then access is less stable and should be reviewed more often. Those changes can also be used as triggers for reviews: to review access whenever someone joins, changes teams, or leaves. The review is meant to catch whatever falls through the cracks of this process, so improving this process should only make your reviews easier going forward.

Whatever cadence you use, when you’re finishing one review, set a reminder for the next one. Teams don't miss reviews because they decided to skip them, they miss them because no one remembered to do them.

Less frequent reviews mean you’re always looking at stale data, which is the argument to move to continuous reviews. One app a week hurts less than forty apps in one week, you catch things sooner, and a missed date stops meaning a missed quarter. Get one full cycle done end to end first, then you can think about moving to continuous reviews.

Who should perform an access review?

At a small company, you can complete an access review with only one or two people, as long as they have access to all the apps you need. You certainly don't need a manager to sign off on each user’s access (unless that’s what your policy says).

Why the set of reviewers often grows is lack of context: who is this user, and should they have access? The person to ask for that context is the app or group owner, not someone’s manager. Questions about who owns a group, and who should be in it, go to the group owner. And questions about what an entitlement permits, e.g., whether "Editor" can delete production records or just change a logo, should go to whoever owns the app.

When there's no owner, or the owner is unavailable, the fallback is IT. Not knowing who owns an app can become problematic at scale, so keep track of owners as you start doing reviews.

Guidance for successfully running access reviews

Review entitlements with enough context to make a decision

The whole point of an access review is to make a decision on each entitlement: should this user have this access? Ask instead: if this person didn't have this access and requested it today, would you grant it? If the answer is an easy yes, approve it. If you'd have questions, that's the entitlement worth spending time reviewing.

A few inputs help here:

  • Does this access match what their peers have? If one user on the support team has production database access and nobody else does, that's unusual and worth reviewing. Conversely, if everyone on the team has it and one person doesn't, that's usually a gap in onboarding rather than a deliberate exception. Peer comparison is why reviewing (and deciding) by group is faster than working down a flat list of users.
  • How did they get it? Access inherited from a role or granted through a group carries its own rationale: someone decided that this group should have this access, and you can review that decision once instead of once per user. Access granted directly has no such rationale attached. It's usually a small share of the entitlements you review and a large share of the remediation that comes out of it.
  • Have they used it? Last login or last activity, where you have it, tells you whether the access is live. Note that some access is legitimately dormant or infrequent, like annual financial reporting, or breakglass production access.

When access isn't critical, removing it by default is the safe move. You can always grant it again, and the request will arrive with more context than you have now. Being unable to explain why an entitlement exists is a reason to remove it, not a reason to keep it.

Fix data quality before the review starts

Access reviews are meant to be a backstop for regular access management, like offboarding that didn't complete or access that was never removed. So don't quietly remediate issues just to make the review look good: a terminated user still holding access is exactly what the review exists to catch.

That doesn't mean every entitlement needs a reviewer's attention. Bulk decisions are fine, and often better — remove everyone who's left the company in a single action before the review goes out.

If you have duplicate accounts, or accounts that should map to a user and don't, fix that before the review. These have an obvious right answer, so routing them to a reviewer spends their attention on work that isn't judgment. And it costs more than the time: a handful of obviously wrong entitlements is enough to make a reviewer distrust the entire dataset.

What reaches a human should be the decisions where human judgment is actually required.

Approve access by group, not user by user

One of the biggest concerns about user access reviews is that they can become a rubber stamping exercise — and it’s not hard for this to happen if you hand someone a spreadsheet with several hundred rows, asking them to review each one carefully.

Wherever you have access based on a group, use that to make reviewing access easier, and to make batch decisions on access. So if everyone in engineering has the same group and the same role in an app, you can make one decision for the whole group, instead of dozens of individual decisions. This is also how you should handle any broad standing access, rather than reviewing access entitlement by entitlement.

After taking these bulk decisions out, spend attention on what actually needs judgment: admin and owner roles, anything touching production or customer data, access granted directly to one user rather than through a group, and anything that changed since last time.

Review group membership and group access separately. Membership changes often, as people move between roles and projects, and belongs to the group owner. What a group can reach should barely change at all, and belongs to the owner of each app the group has access to.

Review all access, not just what changed

Reviewing every entitlement every quarter is how reviews become unbearable, especially when most of what you’re reviewing hasn’t changed. One option is to review just the delta of what has changed: new access, new admins, or anything that’s not inherent access that all employees get.

Use a delta to know where to focus, but don’t review only the delta. The delta review only works if you have a clean baseline to start from, so you still need to review all access regularly. You can then review delta access more often, or in more detail, than the baseline.

Review inherent access as a group

Some access is inherent or “birthright” access, that’s given to all users or all users in a department automatically when they join. There’s an argument for skipping reviewing this access, since it’s defined by policy. However, it’s still important to review that that policy is what’s intended, and that reality matches it.

An access review should cover all access, including inherent access. But instead of reviewing this user by user, review it broadly, to make sure it still makes sense at the company level.

Unlike other parts of an access review, this is also where you’re most likely to catch users who have been under-granted access, and are missing some access needed to do their jobs — resulting in access requests.

Check MFA status and authentication settings while you’re already there

Checking MFA enrollment isn't part of a user access review, but it’s something you might still need to do as part of an audit, for example if your access policy requires MFA on critical apps.

However, as part of doing an access review, you’ve already pulled the list of users from all of your apps, so this is an opportune time to also review how accounts in those apps are secured:

  • Which users are or aren’t enrolled in MFA
  • Which users are signing in with a local password instead of with SSO
  • If the app configuration enforces the use of MFA
  • If the app configuration enforces the use of SSO

This is also a good time to review other ways of accessing an app, including any API keys, service accounts, integrations, or OAuth grants with access to the app.

Reclaim licenses separately

It's tempting, as you're reviewing everyone's access, to use the same pass to reclaim licenses for unused access — but they're not the same thing. An access review asks whether someone should have the access. License reclamation asks whether they're using it. There are many valid reasons for access to sit unused — that’s exactly what breakglass access is for.

None of which makes license reclamation a bad idea, just a separate process, especially since you may need different or additional information than what you have in your access reviews. Last login or last active information is the best input you have for reviewing license usage, and the next best is asking the user directly whether they still need it.

Make a decision for every entitlement, but don’t review each one individually

Every entitlement you review needs an explicit decision made about it: to approve, remove, or change access. There shouldn’t be any blanks. But that doesn’t mean you need to individually consider every entitlement.

You should aim to review access by group as much as possible, and can make some default decisions, like to remove any access for users who are no longer employees or contractors, or to approve any inherent access. Conversely, spend time in your review carefully reviewing any riskier or directly granted access.

Document a rationale for any exceptions

Although every entitlement needs to be explicitly reviewed, only some need additional context, like an explanation. This isn’t required, but helps make your life easier next time you’re completing a review by making a decision about access, or the access itself, more understandable. Often, how a user has access (like through a group) is an explanation in and of itself.

You don’t need to document a decision everywhere — that’s how an access review becomes unbearably long. Instead, add a note only when it helps explain the decision to others:

  • You approved access that looks like it shouldn't be there. Explaining exceptions (in either direction) is most of what notes are for.
  • You have additional context from an app owner that isn’t otherwise captured.
  • You reviewed your own access. This helps others audit that the access review was completed and the access warranted.
  • You knowingly left something in place that probably should go. This is accepting and documenting a risk.

Review separation of duties where possible

Separation of duties is the principle that no single person should be able to complete a risky workflow end to end: submitting and approving an invoice, or writing and shipping code to production. It’s about preventing any one person from performing a risky action unilaterally.

The textbook case is a “toxic” combination of roles that are fine apart and dangerous together. Those exist, but the more common gap sits inside a single app and depends on how that app is configured. Someone with write access to a repo can push straight to production, or can't, depending on whether branch protection requires a second approver. But the entitlement looks the same either way, and reviewing the entitlements alone can’t tell you whether separation of duties holds.

If separation of duties is a concern, treat it as a separate exercise instead, driven by a risk assessment or a threat model rather than by an access review. Name the critical risks in your environment, and identify whether any users have the ability to single-handedly take actions that would realize them today. Where it’s possible, either fix it or accept it with a compensating control, like an approval, alert, or audit log. Where a control genuinely does depend on someone not holding two entitlements, document it and check it in the access review.

Avoid approving your own access where possible

Separation of duties also applies to the review itself. The reviewer's independent judgment is the control, and it stops working when the reviewer is also the subject. So in general, avoid having someone approve their own access.

But again, this is not always possible in a smaller company like a startup. If you're the only person who understands what the production database role does (or the only person with that role), you're the only person who can meaningfully review who holds it, including yourself. Self-approval is acceptable where necessary — where no one else can perform the review.

For any access you approve for yourself that isn't inherent to your role, say why you need it, in terms that another person could understand later. Where the overlap can't be avoided, document who reviewed what.

This is different from asking people to confirm their own access (self-reviews), where you can ask users if they still need the access that they hold. That should be treated as an input to the decision, but not the decision itself.

Track who made each decision, and sign off at the level your policy requires

Who signs off on an access review depends on your access policy, your documented process, or your auditor’s expectations.

Sign-off can happen at different levels of granularity:

  • Per entitlement, where the reviewer’s decision is itself the attestation
  • Per app, where an app owner attests to all the decisions for that app
  • Per review, where whoever runs the review process attests that it happened as documented

Whichever level you sign off at, the underlying record is the same: for every entitlement, who decided, what they decided, and when. Sign-off sits on top of those decisions.

Use what you find to fix how access gets granted

Once the review and its remediations are complete, the review is done — but the value isn't only in the entitlements you fixed. It's in noticing which ones you fix every single time, and going after the cause.

So when you close out a review, look at the remediations as a set rather than one at a time, and ask where they came from.

  • You keep finding stale accounts. Deprovisioning isn't running everywhere it should. Check whether a connection is broken, extend it to the apps it doesn't cover, and add the ones it can't cover to your offboarding checklist.
  • You keep finding overprovisioned people or teams. Either the onboarding template grants too much, or permissions are being cloned from an existing user who already had too much. Make sure a narrower role actually exists to grant instead, tighten the template, and point future requests at the smaller role.
  • You keep removing access for movers. Nothing takes away old access when someone changes teams. Add a step to the transfer process, trigger a review when there's a reorg, or tie the access to group membership so it falls off on its own.

You may also find access that's correct but hard to explain, like the same entitlement granted directly to person after person, when it could be a group or attached to a role. That's worth refactoring even though nothing is technically wrong: access you can reason about in one place is access you can review in one decision.

This is how next quarter's review becomes shorter than this one.

What an access review produces

When your auditor looks at your access review, they won’t check every entitlement, but will select a sample for review, tracing each one end to end: it appeared in this export, someone decided this about it on this date, and here's proof the change happened. That’s why being consistent and comprehensive with your reviews matters.

An access review is meant to produce three pieces of evidence: who had access, what access was reviewed and what decisions were made, and were the remediation actions completed.

Evidence of who had access

To prove you reviewed the correct data, the evidence you need is the raw export from each app, with the date and where it came from. This can be a screenshot, a csv export, or an API response. Keep the original raw data separate from a working copy you might annotate or update.

Keeping this export matters because of how your auditor will test your evidence: they’ll look at this list, pick an entitlement, and ask what you decided about this access. If you regenerated the list later from current state, you’ve lost that information.

You should also keep your app inventory as evidence — it defines the scope of the review. It’s helpful to document how you did this so you can do the same thing at the next review.

Keep all of this at least through the end of your audit period and until the report is issued. If you're doing Type II reports year over year, keeping the last several cycles is what lets you show the control operated continuously rather than once.

Evidence of the decisions you made

Record the decision you made for every entitlement: approve, remove, or change, with who made that decision, and when.

If an access decision needs further explanation, add a note. It’s worth it to annotate access that’s inherent or by default as well.

If you need explicit sign-off for each entitlement, this is where you should track that.

Evidence that the access was removed

Collect evidence that if you decided to remove access, it’s been done, with a date attached. Same goes for changing access. A review where you decided to remove or change access, but didn’t complete the remediation, isn’t complete.

If you’re removing access, ideally tell people before you take their access away. A proactive message lets you avoid surprises (or someone re-requesting that access), and sometimes the reply gives you more context that changes the decision.

Where this gets complicated is when the person running the review can't remove the access. Say the IT or security team runs the review, but then an app owner needs to go make the change; either they forget to, or they don’t collect proof of the change.

Run remediation actions like any other process: use a checklist to make sure everything gets done. Every remediation action you noted, whether a removal or a change of access, should be written down, with somewhere to mark it done. And put a deadline on getting that checklist complete.

This can also go into a ticketing system, with one ticket per item. This is particularly useful when you need to coordinate more than one person to get this work done.

Either way, a closed item only proves somebody said they did it. Verify in the app and keep the post-removal export.

How access reviews usually fail

  • You did the review, but you can't prove it. You made access review decisions in Slack, overwrote the export of access when you ran the next cycle, or lost the review spreadsheet in somebody's personal Drive. If you can't produce it, it didn't happen.
  • You reviewed an incomplete user list. You pulled a list of users from your identity provider instead of from apps directly, missing local accounts, non-SSO tools, and service accounts. You reviewed the wrong scope.
  • You ran it late, or didn't run it at all. A cycle goes by, everyone's busy, and you're busy with other work for your upcoming audit — and you forget to run the review. Set an owner, a calendar reminder, and start early to avoid being late against the cadence you set out in your own policy.
  • You didn’t find anything. Every entitlement was approved and no access changed. A clean result is rare rather than wrong, and it’s less believable for a larger dataset. More likely, you didn’t review the full scope of apps, roles and users you have; or you rubber stamped access because approving was the only way to finish. Batch decisions that are obvious, and make sure a human reviews high-risk and directly granted entitlements.

FAQs


Ready to simplify access management?

Experience the joy of fewer IT tickets

We’d love to help you get to more maintainable access controls