How to restrict frontend pages in React based on user permissions in Django restframework?

I'm developing a web application with Django restframework (backend) and React (frontend). In the backend, I have several endpoints restricted by specific permissions, and that part works well. Now, I need to ensure that in the frontend, each user only sees the pages where they have at least one permission to make changes.

Ideas I've considered for implementation:

Adding a JSON field to the user table that includes a list of accessible pages for each user. This way, I could easily query the accessible pages directly.

During login, along with the token or other response data, map over the user’s permissions to generate a list of accessible pages and send it to the frontend right away.

What would be the best approach to implement this kind of access restriction in the frontend? Is there an established method to manage page access in React based on user permissions received from the backend?

Thank you in advance for any guidance.

Both of your ideas work, but the former will quickly become cumbersome to manage.

I've done the same as your second idea for a fullstack project, but it should be trivial to tweak it to also work for DRF. The advantage of this approach is that, while there's more setup initially, it scales so much better. Whenever you tweak pages, or add new pages, you won't have to iterate over possibly your entire database to update each user's JSON fields to reflect the changes.

Here's the bare essentials of how you can solve it:

# views.py
class ItemDeleteView(views.ModelDeleteView):
    permission_required = "app.remove_item"
    navbar_name         = "Delete item"
# templatetags/navbar.py
def generate_page_list(user: User):
    result_list = []

    for view in view_library:
        if user.has_perm(view.permission_required):
            result_list.append({
                "name": view.navbar_name,
                "url": reverse(view.url_name()),
                "icon": get_icon(view.icon),
            })

    return result_list


@register.inclusion_tag("includes/navbar.html")
def nav(user: User):
    cache_key = get_key(NAVBAR, user)
    pages = cache.get(cache_key)

    if pages is None:
        pages = generate_page_list(user)
        cache.set(cache_key, pages)

    return {'pages': pages}

In DRF you will of course not need templatetags, but I included it just to fully illustrate the idea.

Then, in React, have your login component place pages somewhere useful - either in a context or your favorite state manager, and now the navbar component can load all the information it needs to paint the available pages.

Back to Top