How to Manage Multiple Authors and Roles in EmDash CMS

How to Manage Multiple Authors and Roles in EmDash CMS

EmDash keeps two related but genuinely separate concepts apart: who has a login account and what they're permitted to do (a user, with a role), and who gets public credit on a piece of content (a byline). Understanding that split up front makes the rest of multi-author setup much simpler.

Table of Contents
  1. The Five Roles
  2. Inviting a New User
  3. Bylines: Public Credit, Separate From Login Access
  4. Assigning Multiple Bylines to One Post
  5. A Realistic Editorial Setup
  6. Frequently Asked Questions
  7. Does every byline need a matching user account?
  8. Can I change someone's role after they're already invited?
  9. What happens if a Contributor tries to publish content?
  10. Can a Subscriber write blog posts?
  11. The Bottom Line

The Five Roles

EmDash has five roles, from least to most access: Subscriber, Contributor, Author, Editor, Admin.

What each role can actually do, from the documented AI-tools permission table (the same permissions apply throughout the admin, not just via AI):

  • Admin — everything, including schema changes (creating/deleting collections and fields) and site settings.
  • Editor — all content, media, taxonomies, and menus across the whole site. Can view schema and read settings, but not change them.
  • Author — their own content and media only.
  • Contributor — their own content (drafts only, no publishing) and their own media.
  • Subscriber — the lowest tier, without content-editing access (relevant mainly for sites with member-gated content or comments).

That progression matters for a real editorial team: a freelance writer should usually be a Contributor (drafts something, can't accidentally publish it live), a staff writer an Author, a managing editor an Editor, and only your actual site administrator an Admin.

Inviting a New User

Invite via the REST API, specifying the numeric role:

POST /_emdash/api/auth/invite
Content-Type: application/json

{
  "email": "newwriter@example.com",
  "role": 30
}
emdashkits.com

Or through the admin panel's user management screen if you'd rather not script it — functionally identical, just a form instead of a direct API call.

Read also:

Bylines: Public Credit, Separate From Login Access

A byline is EmDash's concept for "who gets credited publicly on this content" — a name, avatar, and bio that appears on a post, independent of whether that person has (or needs) a login account at all. This matters for a few real scenarios a pure "author = user" model can't handle cleanly:

  • A guest contributor who wrote one piece and shouldn't get a permanent login account.
  • A staff writer whose byline name differs from their internal account (a pen name, or a public-facing display name).
  • Multiple credited contributors on one piece — a primary author plus a co-writer or editor credit — without granting every credited person write access to your CMS.

Assigning Multiple Bylines to One Post

A single content item can carry several ordered byline credits, with one marked as primary. In practice: when publishing a co-written post, add each contributor's byline in the content editor's author/byline field, and set which one is primary — that's the byline used for the main "By [Name]" display, while the others still get credited (commonly in a smaller "with contributions from" line, depending on how your templates render it).

A Realistic Editorial Setup

  1. Create byline profiles for every person who should get public credit, including guest writers without login accounts.
  2. Invite actual team members as users with the role matching their real responsibility (Contributor for occasional writers, Author for regular staff, Editor for the person who reviews and publishes).
  3. Link each user to their own byline where the identities should match, or keep bylines standalone for guest content.
  4. When publishing a multi-author piece, add every contributing byline and mark the lead writer's as primary.

Frequently Asked Questions

Does every byline need a matching user account?

No — that's the whole point of separating the two. A guest contributor can have a byline with no corresponding login user, while your actual CMS editors are users with roles governing what they can do in the admin.

Can I change someone's role after they're already invited?

Yes — role is a property of the user account, updatable by an Admin, and takes effect on their next admin panel action rather than requiring them to be reinvited.

What happens if a Contributor tries to publish content?

They can't — Contributor role is explicitly scoped to draft content only, with no publish permission. Publishing requires Author-level access or higher for that specific content, or an Editor/Admin doing it on their behalf.

Can a Subscriber write blog posts?

No — Subscriber is the lowest-access role and doesn't include content-editing permissions. It's relevant mainly for member/comment-gated features, not for editorial contributors.

The Bottom Line

EmDash's role system (Subscriber through Admin) controls what someone can actually do inside the CMS, while bylines control who gets public credit on content — deliberately decoupled so a guest writer doesn't need a login and a multi-author piece doesn't need every contributor to have publish access. Set both up according to your team's real editorial workflow rather than defaulting everyone to Admin out of convenience.

Share

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

TL;DR — A custom session-cookie login flow appeared to succeed on localhost (the OTP verified, the response looked fine) but every subsequent request to a login-gated page treated the visitor as logged out. Identical code worked fine on the live HTTPS site. The cookie's Secure attribute was hardcoded to true — and per the cookie spec, browsers never store or send a Secure cookie over a plain, non-HTTPS connection.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Fix
  4. Lessons learned

Diagnostic

Check the actual Set-Cookie response header and the browser's own cookie storage panel — on localhost over http://, the cookie is sent by the server but never actually stored by the browser.

Root cause

// before -- assumes the app is always served over HTTPS
setCookie("session", token, { secure: true, httpOnly: true });
emdashkits.com

A cookie config that quietly assumes "we're always on HTTPS" breaks the instant you test over plain HTTP, which local dev servers commonly are.

Read also:

Fix

// after -- derive secure from the actual request protocol
const isHttps = request.url.startsWith("https://");
setCookie("session", token, { secure: isHttps, httpOnly: true });
emdashkits.com

Lessons learned

  • Any Secure-flagged cookie needs to key off the real request scheme, not an assumption baked in once at cookie-creation time.
  • "Works in production, silently fails in local dev" is a strong signal to check cookie flags before anything else in an auth flow.
  • Check other cookies in the same codebase for the same hardcoded assumption — if one cookie has this bug, sibling cookies set the same way are worth auditing too.
Share
Previous Article

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Comments

Write a comment

Related Articles

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

TL;DR — GA4's gtag.js snippet was installed correctly, the page loaded with no visible JavaScript error, and GA4's real-time report still showed zero activity. The CMS's default Content-Security-Policy had no allowance for analytics domains and no config option to add one — so every request to Google's tracking endpoints was blocked at the browser level before it could fail loudly.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Lessons learned

Diagnostic

Check the browser's dedicated CSP violation reporting, not the regular console error list — CSP blocks are reported through their own channel, not thrown as normal script errors, so "no console errors" doesn't mean nothing was blocked.

Root cause

The CSP's script-src and connect-src directives had no entry for googletagmanager.com or google-analytics.com, and the CMS exposed no configuration surface to add one — the only way in was patching the CSP directives directly.

// patch-package: add analytics domains to the existing CSP directives
scriptSrc.push("https://www.googletagmanager.com");
connectSrc.push("https://www.google-analytics.com", "https://www.googletagmanager.com");
emdashkits.com
Read also:

Lessons learned

  • "No console errors" is not proof nothing was blocked — CSP violations live in their own reporting surface and are easy to miss if you're only scanning for red error text.
  • Before adding any third-party script tag to a site with a CSP already in place, check the CSP's directives first rather than assuming a silently-empty analytics dashboard means a snippet-installation mistake.
Share
Previous Article

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Next Article

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)