Skip to main content

User Role Assignment

Overview​

The /api/set-user-role endpoint allows authorized users to assign roles to other users. This endpoint is primarily used for role management and user promotion within the Ring Platform hierarchy.

Authentication​

Required: Admin role or specific permissions Rate Limit: 60 requests per minute for admins, 10 for other authorized users

Endpoint Details​

POST /api/set-user-role

Headers:

Authorization: Bearer <session-token>
Content-Type: application/json

Request​

Body Parameters​

ParameterTypeRequiredDescription
userIdstringYesTarget user ID
rolestringYesNew role to assign
reasonstringNoReason for role change
notifyUserbooleanNoSend notification to user (default: true)

Available Roles​

RoleDescriptionPermissions
visitorBasic accessView public content only
subscriberNewsletter accessPublic content + newsletters
memberFull platform accessAll public features + entity/opportunity creation
confidentialPremium accessMember features + confidential content
adminAdministrative accessFull platform control

Request Example​

{
"userId": "user_123",
"role": "member",
"reason": "User completed verification process",
"notifyUser": true
}

Response​

Success Response (200)​

{
"success": true,
"message": "User role updated successfully",
"data": {
"userId": "user_123",
"previousRole": "subscriber",
"newRole": "member",
"updatedBy": "admin_456",
"updatedAt": "2024-12-14T16:00:00Z",
"reason": "User completed verification process",
"notificationSent": true
}
}

Code Examples​

JavaScript/TypeScript​

// Role assignment service
class RoleService {
async assignRole(
userId: string,
role: string,
reason?: string,
notifyUser = true
) {
try {
const response = await fetch('/api/set-user-role', {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.getSessionToken()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId,
role,
reason,
notifyUser
})
})

if (!response.ok) {
const error = await response.json()
throw new Error(error.message || 'Failed to assign role')
}

return await response.json()
} catch (error) {
console.error('Error assigning role:', error)
throw error
}
}

async promoteToMember(userId: string, reason?: string) {
return this.assignRole(userId, 'member', reason)
}

async promoteToConfidential(userId: string, reason?: string) {
return this.assignRole(userId, 'confidential', reason)
}

async demoteToSubscriber(userId: string, reason?: string) {
return this.assignRole(userId, 'subscriber', reason)
}

private getSessionToken(): string {
// Implementation to get session token
return localStorage.getItem('sessionToken') || ''
}
}

// Usage example
const roleService = new RoleService()

// Promote user to member
await roleService.promoteToMember(
'user_123',
'User completed onboarding process'
)

// Assign confidential role
await roleService.assignRole(
'user_456',
'confidential',
'Verified industry professional',
true
)

React Component​

import { useState } from 'react'
import { useSession } from 'next-auth/react'

interface RoleAssignmentProps {
userId: string
currentRole: string
onRoleChanged?: (newRole: string) => void
}

export function RoleAssignment({
userId,
currentRole,
onRoleChanged
}: RoleAssignmentProps) {
const { data: session } = useSession()
const [selectedRole, setSelectedRole] = useState(currentRole)
const [reason, setReason] = useState('')
const [loading, setLoading] = useState(false)
const [message, setMessage] = useState('')

const roles = [
{ value: 'visitor', label: 'Visitor', description: 'Basic access' },
{ value: 'subscriber', label: 'Subscriber', description: 'Newsletter access' },
{ value: 'member', label: 'Member', description: 'Full platform access' },
{ value: 'confidential', label: 'Confidential', description: 'Premium access' },
{ value: 'admin', label: 'Admin', description: 'Administrative access' }
]

const handleRoleChange = async () => {
if (selectedRole === currentRole) {
setMessage('No change in role')
return
}

try {
setLoading(true)
setMessage('')

const response = await fetch('/api/set-user-role', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId,
role: selectedRole,
reason: reason || `Role changed from ${currentRole} to ${selectedRole}`,
notifyUser: true
})
})

if (!response.ok) {
const error = await response.json()
throw new Error(error.message)
}

const result = await response.json()
setMessage('Role updated successfully')
onRoleChanged?.(selectedRole)

} catch (error) {
setMessage(`Error: ${error.message}`)
} finally {
setLoading(false)
}
}

// Only show to admins or authorized users
if (session?.user?.role !== 'admin') {
return <div>Access denied. Admin privileges required.</div>
}

return (
<div className="role-assignment">
<h3>Role Assignment</h3>

<div className="current-role">
<strong>Current Role:</strong> {currentRole}
</div>

<div className="role-selector">
<label htmlFor="role-select">New Role:</label>
<select
id="role-select"
value={selectedRole}
onChange={(e) => setSelectedRole(e.target.value)}
disabled={loading}
>
{roles.map(role => (
<option key={role.value} value={role.value}>
{role.label} - {role.description}
</option>
))}
</select>
</div>

<div className="reason-input">
<label htmlFor="reason">Reason (optional):</label>
<textarea
id="reason"
value={reason}
onChange={(e) => setReason(e.target.value)}
placeholder="Enter reason for role change..."
disabled={loading}
rows={3}
/>
</div>

<button
onClick={handleRoleChange}
disabled={loading || selectedRole === currentRole}
className="update-role-btn"
>
{loading ? 'Updating...' : 'Update Role'}
</button>

{message && (
<div className={`message ${message.includes('Error') ? 'error' : 'success'}`}>
{message}
</div>
)}
</div>
)
}

cURL Example​

# Assign member role
curl -X POST "https://ring.ck.ua/api/set-user-role" \
-H "Authorization: Bearer admin-session-token" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_123",
"role": "member",
"reason": "User completed verification process",
"notifyUser": true
}'

# Promote to confidential without notification
curl -X POST "https://ring.ck.ua/api/set-user-role" \
-H "Authorization: Bearer admin-session-token" \
-H "Content-Type: application/json" \
-d '{
"userId": "user_456",
"role": "confidential",
"reason": "Industry professional verification",
"notifyUser": false
}'

Error Handling​

Unauthorized Access (403)​

{
"error": "FORBIDDEN",
"message": "Insufficient privileges to assign roles",
"code": 403
}

User Not Found (404)​

{
"error": "USER_NOT_FOUND",
"message": "User with specified ID does not exist",
"code": 404
}

Invalid Role (400)​

{
"error": "INVALID_ROLE",
"message": "Invalid role specified",
"code": 400,
"validRoles": ["visitor", "subscriber", "member", "confidential", "admin"]
}

Cannot Assign Admin Role (400)​

{
"error": "ADMIN_ASSIGNMENT_RESTRICTED",
"message": "Admin role assignment requires special authorization",
"code": 400
}

Self-Assignment Restriction (400)​

{
"error": "SELF_ASSIGNMENT_DENIED",
"message": "Cannot modify your own role",
"code": 400
}

Role Hierarchy and Permissions​

Permission Matrix​

FeatureVisitorSubscriberMemberConfidentialAdmin
View public contentβœ…βœ…βœ…βœ…βœ…
Receive newslettersβŒβœ…βœ…βœ…βœ…
Create entitiesβŒβŒβœ…βœ…βœ…
Create opportunitiesβŒβŒβœ…βœ…βœ…
Access confidential contentβŒβŒβŒβœ…βœ…
Admin panel accessβŒβŒβŒβŒβœ…
User managementβŒβŒβŒβŒβœ…

Role Transition Rules​

interface RoleTransition {
from: string
to: string
requiresApproval: boolean
autoApprove?: boolean
}

const roleTransitions: RoleTransition[] = [
// Promotions
{ from: 'visitor', to: 'subscriber', requiresApproval: false, autoApprove: true },
{ from: 'subscriber', to: 'member', requiresApproval: true },
{ from: 'member', to: 'confidential', requiresApproval: true },
{ from: 'confidential', to: 'admin', requiresApproval: true },

// Demotions
{ from: 'admin', to: 'confidential', requiresApproval: true },
{ from: 'confidential', to: 'member', requiresApproval: false },
{ from: 'member', to: 'subscriber', requiresApproval: false },
{ from: 'subscriber', to: 'visitor', requiresApproval: false }
]

Notification System​

Role Change Notifications​

When a user's role is changed, they receive notifications through multiple channels:

Email Notification​

Subject: Your Ring Platform Role Has Been Updated

Dear [User Name],

Your role on Ring Platform has been updated:
- Previous Role: [Previous Role]
- New Role: [New Role]
- Updated By: [Admin Name]
- Reason: [Reason]

Your new permissions are now active. You can explore your enhanced features by logging into your account.

Best regards,
Ring Platform Team

In-App Notification​

{
"type": "role_change",
"title": "Role Updated",
"message": "Your role has been updated to [New Role]",
"data": {
"previousRole": "subscriber",
"newRole": "member",
"updatedBy": "admin@ring.ck.ua",
"reason": "User completed verification process"
},
"priority": "high",
"timestamp": "2024-12-14T16:00:00Z"
}

Audit and Logging​

Role Change Audit Log​

interface RoleChangeAuditLog {
id: string
userId: string
userEmail: string
previousRole: string
newRole: string
changedBy: string
changedByEmail: string
reason?: string
timestamp: string
ipAddress: string
userAgent: string
notificationSent: boolean
}

Audit Log Example​

{
"id": "audit_role_789",
"userId": "user_123",
"userEmail": "john.doe@example.com",
"previousRole": "subscriber",
"newRole": "member",
"changedBy": "admin_456",
"changedByEmail": "admin@ring.ck.ua",
"reason": "User completed verification process",
"timestamp": "2024-12-14T16:00:00Z",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"notificationSent": true
}

Security Features​

Access Control​

  • Admin Verification: Only admins can assign most roles
  • Self-Assignment Prevention: Users cannot change their own roles
  • Admin Role Protection: Admin role assignment requires special authorization
  • Audit Trail: All role changes are logged and tracked

Rate Limiting​

  • Admin Users: 60 requests per minute
  • Other Authorized Users: 10 requests per minute
  • IP-based Limiting: Additional protection against abuse

Validation​

  • Role Validation: Only valid roles can be assigned
  • User Existence: Target user must exist
  • Permission Checks: Assigner must have sufficient privileges

Testing​

Unit Tests​

describe('Role Assignment API', () => {
test('should assign role with admin privileges', async () => {
const response = await request(app)
.post('/api/set-user-role')
.set('Authorization', `Bearer ${adminToken}`)
.send({
userId: 'user_123',
role: 'member',
reason: 'Test role assignment'
})
.expect(200)

expect(response.body.success).toBe(true)
expect(response.body.data.newRole).toBe('member')
})

test('should reject non-admin role assignment', async () => {
await request(app)
.post('/api/set-user-role')
.set('Authorization', `Bearer ${memberToken}`)
.send({
userId: 'user_123',
role: 'admin'
})
.expect(403)
})

test('should prevent self-role assignment', async () => {
await request(app)
.post('/api/set-user-role')
.set('Authorization', `Bearer ${adminToken}`)
.send({
userId: 'admin_456', // Same as token owner
role: 'member'
})
.expect(400)
})
})

Troubleshooting​

Common Issues​

Issue: "Insufficient privileges to assign roles" Solution: Ensure user has admin role or specific permissions

Issue: "Cannot modify your own role" Solution: Role self-assignment is prohibited for security

Issue: "Admin role assignment requires special authorization" Solution: Admin role assignment has additional security requirements

Issue: "User not found" Solution: Verify the target user ID exists in the system