bitwarden/server · error · UnauthorizedAccessException

Unauthorized.

Error message

Unauthorized.

What it means

Thrown by ValidateAdminRequest (a [NonAction] helper on OrganizationAuthRequestsController) as an UnauthorizedAccessException mapped to HTTP 401 'Unauthorized.' when the current context lacks ManageResetPassword for the org. It is invoked by UpdateAuthRequest, BulkDenyRequests, and UpdateManyAuthRequests, so any admin auth-request action requires the manage-reset-password permission.

Source

Thrown at src/Api/AdminConsole/Controllers/OrganizationAuthRequestsController.cs:88

        {
            await _authRequestService.UpdateAuthRequestAsync(authRequest.Id, authRequest.UserId,
                new AuthRequestUpdateRequestModel { RequestApproved = false, });
        }
    }

    [HttpPost("")]
    public async Task UpdateManyAuthRequests(Guid orgId, [FromBody] IEnumerable<OrganizationAuthRequestUpdateManyRequestModel> model)
    {
        await ValidateAdminRequest(orgId);
        await _updateOrganizationAuthRequestCommand.UpdateAsync(orgId, model.Select(x => x.ToOrganizationAuthRequestUpdate()));
    }

    [NonAction]
    public async Task ValidateAdminRequest(Guid orgId)
    {
        if (!await _currentContext.ManageResetPassword(orgId))
        {
            throw new UnauthorizedAccessException();
        }
    }
}

View on GitHub (pinned to e93b962371)

Solutions

  1. Grant the caller (or the API token's user) the ManageResetPassword permission for the org.
  2. Ensure organization-level password reset / key connector is enabled before calling these endpoints.
  3. Use an Owner/Admin with reset-password rights for admin auth-request automation.
  4. On 401, surface a permission prompt rather than retrying — credentials alone will not fix it.

Example fix

// before
await api.post(`/organizations/${orgId}/auth-requests/${requestId}`, body);

// after
if (!await hasManageResetPassword(orgId)) {
  throw new PermissionError('Manage reset password permission required');
}
await api.post(`/organizations/${orgId}/auth-requests/${requestId}`, body);
Defensive patterns

Strategy: validation

Validate before calling

// Confirm ManageResetPassword for the org before any admin auth-request action
if (!await currentContext.HasManageResetPasswordAsync(orgId))
    throw new PermissionException("Manage reset password permission required");
await api.PostAsync($"/organizations/{orgId}/auth-requests/{requestId}", body);

Type guard

static bool HasResetPermission(OrgAbilities a, Guid orgId)
    => a?.For(orgId)?.ManageResetPassword == true;

Try / catch

try { await api.PostAsync($"/auth-requests/{requestId}", body); }
catch (ApiException e) when (e.StatusCode == HttpStatusCode.Unauthorized)
{ // permission gap, not credentials — prompt for elevation
  throw new PermissionException("Manage reset password required for org", e); }

Prevention

When it happens

Trigger: POSTing to any org auth-request admin endpoint (approve/deny/bulk-deny/bulk-update) as a user whose role does not grant ManageResetPassword for that organization — e.g. a custom admin, a regular manager, or a provider user without reset-password rights.

Common situations: Custom admin role created without the 'Manage reset password' permission; org where password reset is disabled; provider/managed-service user lacking the delegated right; integration using a standard admin token instead of a reset-password-capable one.

Understand the failure class

Related errors


AI-assisted analysis of bitwarden/server@e93b962371 (2026-08-13). Data as JSON: /api/errors/a7885b14ba469b3b. Report an issue: GitHub.