{"record":{"id":"398e59c4441e4f12","repo":"bitwarden/server","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized.","messagePattern":"Unauthorized\\.","errorType":"exception","errorClass":"UnauthorizedAccessException","httpStatus":401,"severity":"warning","filePath":"bitwarden_license/src/Commercial.Core/Billing/Providers/Services/ProviderBillingService.cs","lineNumber":332,"sourceCode":"\n        await csvWriter.WriteRecordsAsync(csvRows);\n\n        await streamWriter.FlushAsync();\n\n        memoryStream.Seek(0, SeekOrigin.Begin);\n\n        return memoryStream.ToArray();\n    }\n\n    public async Task<IEnumerable<AddableOrganization>> GetAddableOrganizations(\n        Provider provider,\n        Guid userId)\n    {\n        var providerUser = await providerUserRepository.GetByProviderUserAsync(provider.Id, userId);\n\n        if (providerUser is not { Status: ProviderUserStatusType.Confirmed })\n        {\n            throw new UnauthorizedAccessException();\n        }\n\n        var candidates = await organizationRepository.GetAddableToProviderByUserIdAsync(userId, provider.Type);\n\n        var active = (await Task.WhenAll(candidates.Select(async organization =>\n            {\n                var subscription = await subscriberService.GetSubscription(organization);\n                return (organization, subscription);\n            })))\n            .Where(pair => pair.subscription is\n            {\n                Status:\n                SubscriptionStatus.Active or\n                SubscriptionStatus.Trialing or\n                SubscriptionStatus.PastDue\n            }).ToList();\n\n        if (active.Count == 0)","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/bitwarden/server/blob/e93b962371d80964556f5590c6615f5160a437a1/bitwarden_license/src/Commercial.Core/Billing/Providers/Services/ProviderBillingService.cs#L314-L350","documentation":"Thrown by ProviderBillingService.GetAddableOrganizations when the requesting providerUser is not Confirmed (null or Status != Confirmed). Only confirmed provider members may list organizations that can be added to the provider. UnauthorizedAccessException (HTTP 401).","triggerScenarios":"Calling GetAddableOrganizations with a userId whose ProviderUser for this provider is Invited, Accepted, or absent entirely.","commonSituations":"A newly invited provider admin who hasn't accepted/confirmed calling the add-org screen; a non-member attempting the call; session belonging to a user not linked to this provider.","solutions":["Require the user to accept and be confirmed on the provider before exposing the add-organizations action.","Gate the UI on the provider membership status; hide the add flow until Confirmed.","Return a clear 401/403 with a message rather than relying on the raw exception in API responses."],"exampleFix":"// before\nvar orgs = await providerBillingService.GetAddableOrganizations(provider, userId);\n\n// after\nvar pu = await providerUserRepository.GetByProviderUserAsync(provider.Id, userId);\nif (pu is not { Status: ProviderUserStatusType.Confirmed })\n    return Unauthorized(\"Confirm your provider membership first.\");\nvar orgs = await providerBillingService.GetAddableOrganizations(provider, userId);","handlingStrategy":"validation","validationCode":"var pu = await providerUserRepository.GetByProviderUserAsync(provider.Id, userId);\nif (pu is not { Status: ProviderUserStatusType.Confirmed }) return Unauthorized(\"Not confirmed.\");","typeGuard":"static bool IsConfirmedMember(ProviderUser? pu) => pu is { Status: ProviderUserStatusType.Confirmed };","tryCatchPattern":null,"preventionTips":["Gate the add-organizations UI on confirmed provider membership.","Return a clear 401/403 message rather than a raw UnauthorizedAccessException."],"tags":["billing","provider","authorization","unauthorized"],"backgroundTag":null,"analyzedSha":"e93b962371d80964556f5590c6615f5160a437a1","analyzedAt":"2026-08-13T14:22:19.382Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}