fullstackhero/dotnet-starter-kit · error · ForbiddenException

Only administrators can change user status.

Error message

Only administrators can change user status.

What it means

UserStatusService.ValidateTogglePermissionsAsync throws ForbiddenException("Only administrators can change user status.") when the authenticated actor is not a member of the Admin role. The failure is first recorded via AuditPolicyFailureAsync before the 403 is raised.

Solutions

  1. Grant the actor the Admin role (assign via the identity module roles endpoint or seed) if they legitimately need this capability.
  2. Sign in as a user with the Admin role instead.
  3. Verify role assignment: check AspNetUserRoles/AspNetRoles for the actor and RoleConstants.Admin.
  4. Re-login to refresh the JWT claims if the role was recently granted.

Example fix

// before (acting as non-admin)
await mediator.Send(new ToggleUserStatusCommand { UserId = targetId });
// after (assert first)
if (!await userManager.IsInRoleAsync(currentUser, RoleConstants.Admin))
    throw new ForbiddenException("Admin role required.");
await mediator.Send(new ToggleUserStatusCommand { UserId = targetId });
Defensive patterns

Strategy: validation

Validate before calling

var isAdmin = await userManager.IsInRoleAsync(actor, RoleConstants.Admin);
if (!isAdmin) return Result.Forbidden("Admin role required.");

Try / catch

try { ... }
catch (ForbiddenException) { notifyUser("You need administrator rights for this action"); }

Prevention

When it happens

Trigger: Any non-admin user calling the toggle-user-status endpoint; an admin whose role assignment was removed before the call; a token issued before a role revocation still carrying the user through.

Common situations: Ordinary users hitting admin-only endpoints from a modified UI; permission config drift where the Admin role constant changed; users with custom roles assumed to have admin rights.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/32fd625bcc35eeae. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Services/UserStatusService.cs:81

            .FirstOrDefaultAsync(cancellationToken)
            ?? throw new NotFoundException("User Not Found.");

        return new ToggleStatusContext(
            ActorId: actorId,
            Actor: actor,
            TargetUser: targetUser,
            ActivateUser: activateUser,
            TenantId: multiTenantContextAccessor?.MultiTenantContext?.TenantInfo?.Id);
    }

    private async Task ValidateTogglePermissionsAsync(
        ToggleStatusContext context,
        CancellationToken cancellationToken)
    {
        if (!await userManager.IsInRoleAsync(context.Actor, RoleConstants.Admin))
        {
            await AuditPolicyFailureAsync(context, "ActorNotAdmin", cancellationToken);
            throw new ForbiddenException("Only administrators can change user status.");
        }

        if (!context.ActivateUser && context.ActorId.ToString() == context.TargetUser.Id)
        {
            await AuditPolicyFailureAsync(context, "SelfDeactivationBlocked", cancellationToken);
            throw new CustomException("Users cannot deactivate themselves.", Array.Empty<string>(), HttpStatusCode.BadRequest);
        }

        if (!context.ActivateUser && await userManager.IsInRoleAsync(context.TargetUser, RoleConstants.Admin))
        {
            await AuditPolicyFailureAsync(context, "AdminDeactivationBlocked", cancellationToken);
            throw new CustomException("Administrators cannot be deactivated.", Array.Empty<string>(), HttpStatusCode.BadRequest);
        }

        if (!context.ActivateUser)
        {
            await EnsureMinimumActiveAdminsAsync(context, cancellationToken);
        }

View on GitHub (pinned to 3f2959e683)