Discussion on hiding views and fields based on group permissions in Sanity.io

16 replies
Last updated: Apr 15, 2020
Anybody have any solutions for this question? Need to figure out if I can hide views and fields based on the 2 built in group permissions available on non enterprise. https://sanity-io-land.slack.com/archives/C9Z7RC3V1/p1586321578058400
AI Update

Yes, you can hide views and fields based on user roles in Sanity Studio, even on non-enterprise plans with the built-in roles! Here's how to do it with current Sanity Studio v3+ APIs:

Hiding Fields Based on User Role

You can use the hidden callback function in your schema fields to conditionally show/hide fields based on the current user's role. The callback receives a context object that includes currentUser:

{
  name: 'sensitiveField',
  type: 'string',
  hidden: ({currentUser}) => {
    const roles = currentUser?.roles.map(r => r.name)
    // Hide for non-admins
    return !roles?.includes('administrator')
  }
}

This is documented in the conditional fields documentation and works in Studio v3+.

Hiding Structure Views Based on Role

For customizing the Structure Builder based on roles, you can access currentUser from the StructureResolverContext that's passed as the second argument to your structure function:

// sanity.config.ts
import {defineConfig} from 'sanity'
import {structureTool} from 'sanity/structure'

export default defineConfig({
  plugins: [
    structureTool({
      structure: (S, context) => {
        const {currentUser} = context
        const isAdmin = currentUser?.roles.some(role => role.name === 'administrator')
        
        if (isAdmin) {
          return S.list()
            .title('Admin Structure')
            .items([
              // All document types
              ...S.documentTypeListItems()
            ])
        }
        
        return S.list()
          .title('Editor Structure')
          .items([
            // Limited document types
            S.documentTypeListItem('post'),
            S.documentTypeListItem('page')
          ])
      }
    })
  ]
})

The context object passed to your structure function includes currentUser, dataset, projectId, schema, and other useful properties as shown in the Structure Builder API reference.

Important Notes

  • Users can have multiple roles - make sure your logic accounts for this by using .some() or similar array methods
  • The currentUser object is available throughout Studio v3+ in context objects and hooks like useCurrentUser()
  • For read-only fields (rather than hidden), you can use the readOnly callback with the same pattern
  • Remember that hiding fields in the Studio is a UX convenience, not a security measure - actual access control for document-level permissions requires Custom Roles (Enterprise feature)

The key is that currentUser is available in many places throughout the modern Studio API, giving you flexibility to customize the Studio experience based on the built-in roles (administrator, editor, etc.) without needing enterprise custom roles!

Here's a super minimal example on a desk structure that's based on roles. It's not exactly what you want perhaps, but it's the way to at least hide document types:
// deskStructure
import S from '@sanity/base/structure-builder'
import userStore from 'part:@sanity/base/user'
import {
  map
} from 'rxjs/operators'

export default () => {
  return userStore.currentUser.pipe(
    map(({user}) => {
      const {role} = user
      if (role === 'administrator') {
        return S.list().title('Admin structure')
      }
      return S.list().title('Editor structure')
    })
  )
}

thanks
Knut Melvær
so can I do something similar with displaying fields like in the conditional input field?
I'm testing if you can set
hide: process.env.SANITY_STUDIO_HIDE
on a field to at leat be able to build a studio for an editor with less visible fields
oh sweet yeah that would be all I need, just want to clean up the interface for non admins to only what they should see
Aight, so that actually works.

{
  name: 'fieldForHighPayGrade',
  type: 'string',
  title: 'C-suite level field',
  hidden: !!process.env.SANITY_STUDIO_HIDE
}
This field will be hidden if you run

SANITY_STUDIO_HIDE=true sanity start
or

SANITY_STUDIO_HIDE=true sanity build
or has the env set in a dotenv file.
This means that you can for example build two studios on Netlify for example, one for admins and one for others. Using the same codebase, but adding the env variable for the one.
ah ok gotcha that works but would rather check the user dynamically at runtime and have one studio, would something similar to the original code work in a conditional field?
Then you need to use custom input fields that uses the userStore I used in the structure example. It's on our roadmap to give you more and easier control over field display though.
ok cool thanks I think I have all I need then, appreciate the code snippets and alternatives
also when you say on our roadmap is it like this quarter or later this year or not sure yet 🙂
Probably not this quarter 🙂 But very probably this year
ok thanks!
Knut Melvær
when you're back online, no rush that snippet for checking the user is admin or not only seems to work in some places. If I call it for instance in a workflow action it gets in a refresh/login screen loop even though the user is logged in. Just wondering why it would matter where you call it and is there some way around that so I can use it everywhere?
That was… unexpected. I'll check in with the team what's going on.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?