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 |
| Client | Requires login with client 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 client 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: "client" # Any client 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-client access
To restrict a page to specific clients, use the client: prefix with a comma-separated list of client folder names:
access: "client:dianomi" # Only the "dianomi" client
access: "client:dianomi,acme" # "dianomi" or "acme" clients
access: "client:dianomi,acme,globex" # Any of these three clients
Team and admin users always have access regardless of the client list. The client folder names must match the clientFolder 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="client:dianomi,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
- The generator checks for
_defaults.mdin the same directory as the page being processed - Default values are merged — page frontmatter always wins over folder defaults
_defaults.mdfiles are never generated into HTML pages (skipped during generation)
Current defaults
# cms/_defaults.md
---
access: "team"
---
# cms/clients/dianomi/_defaults.md
---
access: "client:dianomi"
---
# cms/clients/client-template/_defaults.md
---
access: "client:client-template"
---
This means:
- All main docs default to team access
- All dianomi pages default to client:dianomi access
- All client-template pages default to client:client-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
---
accesscontrols who can see the documentation pagetoolAccesscontrols 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="client:dianomi,client-template">
When adding a new client 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:
- Go to your site in the Netlify Dashboard
- Navigate to Integrations → Identity
- 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:
- Click on the user in the Identity list
- Under Metadata, edit the
app_metadatafield - Set the role:
{
"roles": ["admin"]
}
Available roles: admin, team, client.
Client Folder Access
Client users need a role that identifies which client folder they belong to. The simplest way is to add the client folder name as a role tag in the Netlify UI:
Option A — Single tag (recommended)
Add just the client name as a role tag (e.g. dianomi). The system automatically treats any non-hierarchy role as a client folder name and assigns the client access level.
Option B — Two tags (explicit)
Add both client and the client name as tags (e.g. client + dianomi). This is more explicit but functionally identical.
Option C — API (app_metadata)
If using the Netlify API, you can set clientFolder explicitly:
{
"roles": ["client"],
"clientFolder": "dianomi"
}
All three options produce the same result: the user can access pages with data-access="client:dianomi" (or public). They cannot see pages scoped to other clients.
Team and admin users can access all client folders.
Adding a New Client
- Create
cms/clients/acme/_defaults.md:--- access: "client:acme" --- - Create
cms/clients/acme/welcome.md(copy from client-template) - Add theme entry in
assets/js/theme-config.js(css, fonts, label, pages — no access config) - Update shared pages the client should see: add
acmetotoolAccesscomma lists in the relevantcms/*.mdfiles - Update the matching tool HTML pages: add
acmetodata-accesson<body> - Run
npm run docgen
Adding a New Page
- Create the page as usual
- Set the
accessfrontmatter (for docs) ordata-accessattribute (for standalone HTML) - If the page is in a folder with
_defaults.md, you can omitaccess:to inherit the default - Run
npm run docgenif it's a docs page - 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 client.
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: "client:dianomi" |
Role = ["client-dianomi", "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@dianomi.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 client-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_metadatacontains a validrolesarray
User sees "Access Denied" unexpectedly
- Check the user's role tags in the Netlify Identity dashboard
- Verify the page's
data-accessattribute matches the user's role - For client users, ensure one of their role tags matches the client name in
data-access="client:name"(e.g. a user with thedianomitag can accessdata-access="client:dianomi")
Auth not working locally
- Netlify Identity requires a deployed Netlify site. Use
netlify devfor local testing with Identity support.