bitwarden/server · error · NotFoundException

Resource not found.

Error message

Resource not found.

What it means

Thrown by ListByOrganizationAsync (GET /organizations/{organizationId}/service-accounts) when _currentContext.AccessSecretsManager(organizationId) returns false. The 404 intentionally hides the existence of service accounts from callers without SM access for the org.

Source

Thrown at src/Api/SecretsManager/Controllers/ServiceAccountsController.cs:93

        _serviceAccountSecretsDetailsQuery = serviceAccountSecretsDetailsQuery;
        _createServiceAccountCommand = createServiceAccountCommand;
        _updateServiceAccountCommand = updateServiceAccountCommand;
        _deleteServiceAccountsCommand = deleteServiceAccountsCommand;
        _revokeAccessTokensCommand = revokeAccessTokensCommand;
        _pricingClient = pricingClient;
        _createAccessTokenCommand = createAccessTokenCommand;
        _updateSecretsManagerSubscriptionCommand = updateSecretsManagerSubscriptionCommand;
        _eventService = eventService;
        _globalSettings = globalSettings;
    }

    [HttpGet("/organizations/{organizationId}/service-accounts")]
    public async Task<ListResponseModel<ServiceAccountSecretsDetailsResponseModel>> ListByOrganizationAsync(
        [FromRoute] Guid organizationId, [FromQuery] bool includeAccessToSecrets = false)
    {
        if (!_currentContext.AccessSecretsManager(organizationId))
        {
            throw new NotFoundException();
        }

        var userId = _userService.GetProperUserId(User).Value;
        var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
        var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin);

        var results =
            await _serviceAccountSecretsDetailsQuery.GetManyByOrganizationIdAsync(organizationId, userId, accessClient,
                includeAccessToSecrets);
        var responses = results.Select(r => new ServiceAccountSecretsDetailsResponseModel(r));
        return new ListResponseModel<ServiceAccountSecretsDetailsResponseModel>(responses);
    }

    [HttpGet("{id}")]
    public async Task<ServiceAccountResponseModel> GetByServiceAccountIdAsync(
        [FromRoute] Guid id)
    {
        var serviceAccount = await _serviceAccountRepository.GetByIdAsync(id);

View on GitHub (pinned to e93b962371)

Solutions

  1. Confirm Secrets Manager is enabled on the target organization.
  2. Ensure the authenticated user or service account has SM access for that orgId.
  3. Regenerate or refresh the access token after SM access was granted.
Defensive patterns

Strategy: validation

Validate before calling

// Verify SM access before listing service accounts
if (!currentContext.AccessSecretsManager(organizationId))
{
    return Forbid();
}
var result = await serviceAccountsClient.ListByOrganizationAsync(organizationId);

Prevention

When it happens

Trigger: GET /organizations/{organizationId}/service-accounts by a caller who does not have Secrets Manager access for the specified organization — SM not enabled on the org, or the token's claims don't include SM access for that org.

Common situations: Listing service accounts before SM is provisioned; using a personal API key that predates the org's SM enrollment; querying an org the user was removed from.

Related errors


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