Secure Document Editing with Role-Based Access in React Word Editor


TL;DR: Learn how to implement role-based editing in a React Word Editor using Syncfusion® and ASP.NET Core. This guide shows how to restrict document sections and define editable regions in Word documents based on user roles, ensuring secure collaboration that only authorized users can modify specific content.
In today’s collaborative development environments, securing document workflows is more than a feature; it’s a necessity. But how do you ensure that only authorized users can edit specific sections of a document while keeping the rest locked down?
In this article, you’ll learn how to build a role-based document editor using Syncfusion’s React Word Document Editor and ASP.NET Core. We’ll walk through implementing Restrict Editing, a feature that allows registered users to edit only designated regions of a Word document based on their roles. This approach helps maintain document integrity, enforce access control, and streamline collaboration in enterprise-grade applications.
Use case: Vendor agreement workflow
To demonstrate the value of role-based editing, let’s consider a vendor agreement that typically includes terms related to pricing, delivery timelines, confidentiality, and liability. In a collaborative environment, different departments are responsible for various sections of the agreement. Allowing unrestricted editing can lead to accidental or unauthorized changes, potentially resulting in legal or operational issues.
Role-based edit access
Here’s how editing access can be structured based on user roles:
Role | Edit access level |
HR team | Can edit the introduction, including vendor and buyer details, and the agreement date. |
Legal team | Has access to sections on confidentiality, limitation of liability, termination, and jurisdiction & governing law. |
Finance team | Can edit the payment terms and related financial details. |
Project leader | Can modify the scope of work, deliverables, and timeline. |
Using Syncfusion’s Restrict Editing feature, these access levels can be enforced to ensure that each role interacts only with the relevant sections of the document.
Creating a role-based editing document in React
To implement role-based editing restrictions, follow the steps to create a restricted editing document using the Syncfusion® React Word Processor:
Step 1: Create a React app
Start creating a React application and integrating the Syncfusion® Word Document Editor component. This integration enables you to configure and manage restricted editing features within your application.
Step 2: Load the input document
Prepare your sample Word document and load it into the Syncfusion® Word Processor. Navigate to the toolbar and click on the Restrict Editing option under the Review tab. Then, choose the Protections setting to begin configuring access controls, as illustrated below.
Restrict Editing option under the review tab in the Syncfusion Word Editor Toolbar
Step 3: Add user roles
Click on More Users to define the roles or usernames with specific editing permissions. Then enter the desired usernames and add them to the user collection.
Dialog for adding users with editing permissions
Step 4: Assign editable regions
Select the text region that should be editable by a particular user. Click the checkbox next to the corresponding user to assign editing rights for that section.
Assigning a text region to a specific user
Step 5: Enable protection
Once all editable regions are assigned, click Yes, Start Enforcing Protection to activate restricted editing. You’ll need to provide a password for the user you added, which will be required to modify protected sections of the document.
You can then download the protected document and use it in your application or sample workflow.
Note: In this example, we have included the Vendor_Agreement document with restricted editing already applied. However, you can also use your document with predefined restrictions by opening it in the Document Editor.
Setting up ASP.NET Core Backend
To manage user authentication and securely handle document access based on user roles, you’ll need a backend service. In this example, we’ll use ASP.NET Core Web API to implement the necessary endpoints.
Step 1: Create a new ASP.NET Core Web API project
Create an ASP.NET Core Web API project using Visual Studio or the .NET CLI. This project will be the backend for managing user authentication and related operations.
Step 2: Create API endpoints
Create a controller named AuthenticationController.cs with two key endpoints:
Register: Allows new users to register by providing credentials such as username, email ID, and password.
Login: Authenticates existing users using their email ID and password.
These endpoints will internally handle the logic for securely storing and retrieving user data from a users.json file.
AuthenticationController.cs
// Register the new user with the credentials like Username, Email ID and Password
[HttpPost("register")]
public IActionResult Register([FromBody] User newUser)
{
var Users = LoadUsers();
if (Users.Any(u => u.Username == newUser.Username))
{
return BadRequest(new { message = "Username already exists" });
}
if (Users.Any(u => u.Email == newUser.Email))
{
return BadRequest(new { message = "Email already registered" });
}
newUser.Password = BCrypt.Net.BCrypt.HashPassword(newUser.Password);
Users.Add(newUser);
var json = JsonSerializer.Serialize(Users, new JsonSerializerOptions { WriteIndented = true });
System.IO.File.WriteAllText(_userFilePath, json);
return Ok(new { message = "User registered successfully" });
}
// Existing user can login using the credentials such as Email ID and password
[HttpPost("login")]
public IActionResult Login([FromBody] User login)
{
var Users = LoadUsers();
var user = Users.FirstOrDefault(u => u.Email == login.Email);
if (user == null || !BCrypt.Net.BCrypt.Verify(login.Password, user.Password))
{
return Unauthorized(new { message = "Invalid credentials" });
}
return Ok(new { username = user.Username, email = user.Email });
}
Setting up React Frontend
With the backend in place, let’s implement the frontend logic to authenticate users and apply role-based editing.
Step 1: Implement the authentication form
Create a new JavaScript file named Authentication.js to implement the user authentication form and its associated operations. This component will handle both user registration and login, capturing credentials such as email and password, and communicating with the backend API for authentication.
Authentication.js
import { useState } from "react";
import "./index.css"; // Make sure this CSS file exists and is correctly styled
const hostURL = "https://localhost:44310/api/Authentication";
function Authentication({ onLogin }) {
const [isRegistering, setIsRegistering] = useState(false);
const [message, setMessage] = useState("");
const [username, setUsername] = useState("");
const validateEmail = (email) => /\S+@\S+\.\S+/.test(email);
const handleLogin = async (event) => {
event.preventDefault();
setMessage("");
const form = event.currentTarget;
const email = form.elements.email.value.trim();
const password = form.elements.password.value.trim();
if (!validateEmail(email)) {
setMessage("❌ Please enter a valid email.");
return;
}
try {
const response = await fetch(`${hostURL}/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
if (response.ok) {
const userData = await response.json();
localStorage.setItem("user", JSON.stringify(userData));
onLogin(userData);
}
else {
setMessage("❌ Invalid email or password.");
}
} catch {
setMessage("⚠️ Server error during login.");
}
};
const handleRegister = async (e) => {
e.preventDefault();
setMessage("");
const form = e.currentTarget;
const email = form.elements.email.value;
const password = form.elements.password.value;
if (!validateEmail(email)) {
setMessage("❌ Please enter a valid email.");
return;
}
try {
const register = await fetch(`${hostURL}/register`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, email, password }),
});
const data = await register.json();
if (register.ok) {
setMessage("✅ Registration successful. You can now log in.");
setIsRegistering(false);
setUsername("");
}
else {
setMessage(`❌ ${data.message || "Registration failed"}`);
}
} catch {
setMessage("⚠️ Server error during registration.");
}
};
return (
<div className="auth-container">
<h2 className="auth-title">{isRegistering ? "Register" : "Login"}</h2>
<form className="auth-form" onSubmit={isRegistering ? handleRegister : handleLogin}>
{isRegistering && (
<label className="auth-label" htmlFor="username">Username:</label>
<input
id="username"
type="text"
name="username"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
className="auth-input"
placeholder="Your username"/>
)}
<label className="auth-label" htmlFor="email">Email:</label>
<input
id="email"
type="email"
name="email"
required
className="auth-input"
placeholder="you@example.com"/>
<label className="auth-label" htmlFor="password">Password:</label>
<input
id="password"
type="password"
name="password"
required
className="auth-input"
placeholder="Your password"/>
<button type="submit" className="auth-button primary">
{isRegistering ? "Register" : "Login"}
</button>
</form>
<button
className="auth-button secondary"
onClick={() => {
setIsRegistering(!isRegistering);
setMessage("");
setUsername("");
}}
style={{ marginTop: 12 }}>
{isRegistering ? "Already have an account? Log in" : "Don't have an account? Register"}
</button>
{message && <p className="auth-message">{message}</p>}
</div>
);
}
export default Authentication;
To demonstrate role-based editing, this example uses a lightweight local authentication system. User credentials, including username, email, and password, are stored in a local users.json file. When a user logs in via the browser interface, their credentials are validated against this file.
Once authenticated, the system identifies the user and dynamically unlocks only the editable regions assigned to them. All other sections remain read-only, ensuring a secure and controlled editing experience.
Note: Ensure to register using the same username and password that were used to create the document with restricted editing.
This authentication flow can be customized and integrated with your application’s user management system. Doing so allows you to enforce role-based access control post-login, ensuring users can interact only with the sections of the document relevant to their assigned roles.
The authentication form will appear as follows:
Login and registration interface
Step 2: Implement Word Document operations
Create a new JavaScript file named DocumentEditor.js to implement the Word Document Editor functionality. This includes restricting editing based on the role of the currently logged-in user.
DocumentEditor.js
function DocumentEditor() {
const [user, setUser] = useState(null);
const titleBarRef = useRef(null);
const containerRef = useRef(null);
useEffect(() => {
const saved = localStorage.getItem("user");
if (saved) {
setUser(JSON.parse(saved));
}
}, []);
useEffect(() => {
if (user && containerRef.current) {
convertDocxToSfdt();
containerRef.current.documentEditor.documentName = "Document";
containerRef.current.documentEditor.currentUser = user.email;
titleBarRef.current = new TitleBar(
document.getElementById("documenteditor_titlebar"),
containerRef.current.documentEditor,
true
);
titleBarRef.current.updateDocumentTitle();
containerRef.current.documentChange = () => {
titleBarRef.current.updateDocumentTitle();
containerRef.current.documentEditor.focusIn();
};
}
}, [user]);
// Convert GitHub Raw document to SFDT and load in Editor.
const convertDocxToSfdt = async () => {
try {
const docxResponse = await fetch('https://raw.githubusercontent.com/SyncfusionExamples/Role-Based-Access-and-Restrict-Editing-in-React-Word-Editor/master/Client-side/public/docs/Vendor_Agreement.docx');
const docxBlob = await docxResponse.blob();
const formData = new FormData();
formData.append('files', docxBlob, 'Vendor_Agreement.docx');
const importResponse = await fetch('https://ej2services.syncfusion.com/production/web-services/api/documenteditor/Import', {
method: 'POST',
body: formData,
});
if (importResponse.ok) {
defaultDocument = await importResponse.text();
containerRef.current.documentEditor.open(defaultDocument);
}
else {
console.error(`Failed to import document: ${importResponse.statusText}`);
}
} catch (error) {
console.error('Error converting document:', error);
}
};
const logout = () => {
localStorage.removeItem("user");
setUser(null);
};
if (!user) {
return <Authentication onLogin={setUser} />;
}
return (
<div>
<div className="main-titlebar" style={{ display: "flex", justifyContent: "space-between", padding: "8px 12px", alignItems: "center", background: "#f0f0f0" }}>
<p className="welcome-text" style={{ margin: 0 }}>Welcome, {user.username || user.email}</p>
<button className="logout-btn" onClick={logout}>Logout</button>
</div>
<div id="documenteditor_titlebar" className="e-de-ctn-title"></div>
<style>
{`.e-toolbar-items {
display: flex !important;
justify-content: center !important;
}`}
</style>
<DocumentEditorContainerComponent
ref={containerRef}
id="container"
height="calc(100vh - 92px)"
enableToolbar={true}/>
</div>
);
}
export default DocumentEditor;
To implement role-based editing, it’s essential to identify the active user within the document editor. This allows the application to manage user-specific changes, comments, and permissions effectively.
The key step is assigning the current user’s identity to the editor instance using the following line of code:
containerRef.current.documentEditor.currentUser = user.email;
This sets the currentUser property of the document editor to the logged-in user’s email. Once assigned, the editor uses this identity to determine which regions of the document the user is permitted to edit, based on predefined permissions embedded in the document.
By doing so, the editor ensures:
Only authorized sections are editable by the user.
All other content remains locked, preserving document integrity.
This simple assignment forms the bridge between your authentication logic and the document’s editing permissions, establishing the foundation of your role-based access control system.
Below are visual examples highlighting the editable content for each user role, illustrating how specific document sections appear based on assigned permissions.
HR:
Editable sections for HR
Project Leader:
Editable sections for Project Leader
Finance Team:
Editable sections for Finance Team
Legal Team:
Editable sections for Legal Team
Testing the user roles
To test the application, run the server-side (ASP.NET Core API) first, followed by the client-side (React) application.
Use the following login credentials for each user role:
Role | Password | |
HR | hr@gmail.com | 123456 |
Project leader | projectleader@gmail.com | 123456 |
Finance team | financeteam@gmail.com | 123456 |
Legal team | legalteam@gmail.com | 123456 |
GitHub reference
For the complete working projects, refer to the GitHub demo.
Conclusion
By combining Syncfusion’s Restrict Editing capabilities with ASP.NET Core authentication, developers can build secure, scalable document workflows. This approach not only enforces granular access control but also enhances operational efficiency, reduces the likelihood of unauthorized modifications, and ensures regulatory compliance.
As a result, teams can collaborate with confidence, knowing that sensitive content remains protected and workflows remain streamlined. This integration represents a forward-thinking solution for modern enterprises seeking to balance flexibility with security in their document processes.
The new version is available for current customers to download from the license and downloads page. If you are not a Syncfusion® customer, you can try our 30-day free trial for our newest features.
You can also contact us through our support forum, support portal, or feedback portal. We are always happy to assist you
Related Blogs
Subscribe to my newsletter
Read articles from syncfusion directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

syncfusion
syncfusion
Syncfusion provides third-party UI components for React, Vue, Angular, JavaScript, Blazor, .NET MAUI, ASP.NET MVC, Core, WinForms, WPF, UWP and Xamarin.