⚠️ Design system CSS not found. Check the path in cms/docs.config.js → designSystemPath, then re-run npm run docgen.

Access Control

Managing user authentication and page permissions

Docs / Access Control
Download .md file
Open .md in new tab

This site uses Netlify Identity for authentication. Users are invited by email, assigned a role, and can only access pages permitted by their role.

Access Levels

There are four access levels, from lowest to highest privilege:

Level Description
Public No login required, anyone can view
Brand Requires login with brand role or higher
Team Requires login with team role or higher (default)
Admin Requires login with admin role only

Higher roles inherit access from lower roles. An admin can see everything a team member can see, and a team member can see everything a brand can see.

Single Source of Truth

All access rules live in markdown frontmatter. This is the only place access is configured, not in JavaScript, not in theme config files.

The doc generator reads frontmatter and outputs data-access attributes on the HTML. The auth script reads those attributes at runtime and enforces them.

frontmatter (cms/*.md) → generator → data-access (HTML) → auth.js (runtime)

Page Access Configuration

Standard roles

access: "public"    # No login required
access: "brand"    # Any brand or higher
access: "team"      # Team members and admins (default)
access: "admin"     # Admins only

Pages without an access value inherit from _defaults.md in their folder (see below). If no defaults file exists, the fallback is team.

Per-brand access

To restrict a page to specific brands, use the brand: prefix with a comma-separated list of brand folder names:

access: "brand:acme"              # Only the "acme" brand
access: "brand:acme,acme"         # "acme" or "acme" brands
access: "brand:acme,acme,globex"  # Any of these three brands

Team and admin users always have access regardless of the brand list. The brand folder names must match the brandFolder value in the user's Netlify Identity app_metadata.

On standalone HTML pages

Set the attribute directly on <body>:

<body class="auth-loading" data-access="brand:acme,acme">

Folder Defaults (_defaults.md)

Any directory in cms/ can contain a _defaults.md file that sets default frontmatter values for all sibling markdown files in that directory. This works like Notion's inherited permissions. Set it once at the folder level, override per-page when needed.

How it works

  1. The generator checks for _defaults.md in the same directory as the page being processed
  2. Default values are merged, page frontmatter always wins over folder defaults
  3. _defaults.md files are never generated into HTML pages (skipped during generation)

Current defaults

# cms/_defaults.md
---
access: "team"
---

# cms/brands/acme/_defaults.md
---
access: "brand:acme"
---

# cms/brands/brand-template/_defaults.md
---
access: "brand:brand-template"
---

This means:

  • All main docs default to team access
  • All acme pages default to brand:acme access
  • All brand-template pages default to brand:brand-template access
  • Any page can override its folder default with an explicit access: in its own frontmatter

Tool Access

Tools have two access levels, one for the documentation page and one for the tool app itself:

# cms/calculator-docs.md
---
access: "admin"                              # doc page: admin only
toolUrl: "../tools/cpm-calculator.html"
toolAccess: "public"                         # tool app: anyone
---
  • access controls who can see the documentation page
  • toolAccess controls who sees the tool card in section overviews and who can access the tool app page

The standalone tool HTML pages (tools/*.html) must have a matching data-access attribute on their <body>:

<!-- tools/cpm-calculator.html -->
<body class="auth-loading" data-access="public">

<!-- tools/display-ad-preview.html -->
<body class="auth-loading" data-access="brand:acme,brand-template">

When adding a new brand that should see a tool, update the toolAccess field in the markdown file and the data-access attribute on the tool HTML page.

Managing Users

Users are managed in the Netlify Dashboard:

  1. Go to your site in the Netlify Dashboard
  2. Navigate to Integrations → Identity
  3. Click Invite users to send email invitations

Assigning Roles

After a user accepts their invitation, edit their profile in the Identity panel to set their role:

  1. Click on the user in the Identity list
  2. Under Metadata, edit the app_metadata field
  3. Set the role:
{
  "roles": ["admin"]
}

Available roles: admin, team, brand.

Brand Folder Access

Brand users need a role that identifies which brand folder they belong to. The simplest way is to add the brand folder name as a role tag in the Netlify UI:

Option A: Single tag (recommended)

Add just the brand name as a role tag (e.g. acme). The system automatically treats any non-hierarchy role as a brand folder name and assigns the brand access level.

Option B: Two tags (explicit)

Add both brand and the brand name as tags (e.g. brand + acme). This is more explicit but functionally identical.

Option C: API (app_metadata)

If using the Netlify API, you can set brandFolder explicitly:

{
  "roles": ["brand"],
  "brandFolder": "acme"
}

All three options produce the same result: the user can access pages with data-access="brand:acme" (or public). They cannot see pages scoped to other brands.

Team and admin users can access all brand folders.

Adding a New Brand

  1. Create cms/brands/acme/_defaults.md:
    ---
    access: "brand:acme"
    ---
    
  2. Create cms/brands/acme/welcome.md (copy from brand-template)
  3. Add theme entry in assets/js/theme-config.js (css, fonts, label, pages), no access config
  4. Update shared pages the brand should see: add acme to toolAccess comma lists in the relevant cms/*.md files
  5. Update the matching tool HTML pages: add acme to data-access on <body>
  6. Run npm run docgen

Adding a New Page

  1. Create the page as usual
  2. Set the access frontmatter (for docs) or data-access attribute (for standalone HTML)
  3. If the page is in a folder with _defaults.md, you can omit access: to inherit the default
  4. Run npm run docgen if it's a docs page
  5. Deploy. The auth script handles the rest

Element-Level Visibility

Individual elements on a page can be shown or hidden based on the user's role. Add a data-auth-role attribute to any HTML element:

<!-- Only visible to admin -->
<div data-auth-role="admin">
  This content is only visible to administrators.
</div>

<!-- Visible to team and above -->
<div data-auth-role="team">
  This content is visible to team members and admins.
</div>

<!-- Visible to everyone (no login needed) -->
<div data-auth-role="public">
  This content is always visible.
</div>

Role inheritance applies: an admin can see elements marked team or brand.

Login and Logout

  • Login: The Netlify Identity widget opens automatically on protected pages when no user is logged in. A login button is also available in the sidebar.
  • Logout: A logout button appears in the sidebar when logged in. Clicking it clears the session and redirects to the homepage.

Future Enhancements

Server-Side Enforcement

The frontmatter schema maps directly to Netlify redirect rules for server-side enforcement:

Frontmatter Netlify Role Condition
access: "public" No rule needed
access: "team" Role = ["team", "admin"]
access: "admin" Role = ["admin"]
access: "brand:acme" Role = ["brand-acme", "team", "admin"]

A build script could auto-generate netlify.toml redirect rules from frontmatter.

Per-User Access

When needed, extend the frontmatter syntax:

access: "user:erlen@bydefault.studio,jane@acme.com"

This would require storing allowed emails in Netlify Identity metadata and checking against them in auth.js.

Security Notes

  • On the free Netlify tier, authentication is enforced brand-side. The HTML is still served to all visitors, but the JavaScript hides content from unauthenticated or unauthorised users.
  • This is appropriate for internal documentation. It is not suitable for highly sensitive data.
  • For true server-side protection, upgrade to Netlify Pro and add role-based redirect rules in netlify.toml.

Troubleshooting

User can't log in

  • Ensure Identity is enabled in the Netlify Dashboard
  • Check that the user has been invited and has accepted their invitation
  • Verify the user's app_metadata contains a valid roles array

User sees "Access Denied" unexpectedly

  • Check the user's role tags in the Netlify Identity dashboard
  • Verify the page's data-access attribute matches the user's role
  • For brand users, ensure one of their role tags matches the brand name in data-access="brand:name" (e.g. a user with the acme tag can access data-access="brand:acme")

Auth not working locally

  • Netlify Identity requires a deployed Netlify site. Use netlify dev for local testing with Identity support.
On this page
  • Access Levels
  • Single Source of Truth
  • Page Access Configuration
  • Tool Access
  • Managing Users
  • Adding a New Brand
  • Adding a New Page
  • Element-Level Visibility
  • Login and Logout
  • Future Enhancements
  • Security Notes
  • Troubleshooting
Previous

Login Scenarios

Next

Brand Setup

Was this page helpful?

We use this feedback to improve our documentation.

Thanks for your feedback

Send feedback

© 2026 By Default