{"record":{"id":"956a80f1b3e9955d","repo":"dotnet/orleans","slug":"product-management-authorization-is-required","errorCode":null,"errorMessage":"Product management authorization is required.","messagePattern":"Product management authorization is required\\.","errorType":"http","errorClass":"UnauthorizedAccessException","httpStatus":401,"severity":"error","filePath":"samples/Deployment/AzureAppService/Silo/Services/ProductService.cs","lineNumber":19,"sourceCode":"// Copyright (c) Microsoft. All rights reserved.\n// Licensed under the MIT License.\n\nnamespace Orleans.ShoppingCart.Silo.Services;\n\npublic sealed class ProductService(\n    IClusterClient client,\n    IAuthorizationService authorizationService)\n{\n    public async Task CreateOrUpdateProductAsync(\n        ClaimsPrincipal user,\n        ProductDetails product)\n    {\n        var authorizationResult = await authorizationService.AuthorizeAsync(\n            user,\n            AuthorizationPolicies.ProductManagement);\n        if (!authorizationResult.Succeeded)\n        {\n            throw new UnauthorizedAccessException(\n                \"Product management authorization is required.\");\n        }\n\n        await client.GetGrain<IProductGrain>(product.Id).CreateOrUpdateProductAsync(product);\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/samples/Deployment/AzureAppService/Silo/Services/ProductService.cs#L1-L26","documentation":"An UnauthorizedAccessException thrown by ProductService.CreateOrUpdateProductAsync when ASP.NET Core's IAuthorizationService.AuthorizeAsync against the 'ProductManagement' policy returns Succeeded == false. The grain call is gated behind authorization, so an unauthenticated or under-privileged caller is refused before any grain mutation occurs.","triggerScenarios":"A request to create/update a product arrives with a ClaimsPrincipal that does not satisfy the ProductManagement authorization policy (e.g., missing the required role/claim, or anonymous). authorizationResult.Succeeded is false.","commonSituations":"The caller's token lacks the product-management role/claim. The authorization policy is misconfigured (wrong scheme, missing role mapping). The endpoint isn't requiring authentication so the principal is anonymous.","solutions":["Ensure the caller authenticates and the token carries the claim/role the ProductManagement policy requires.","Verify the AuthorizationPolicies.ProductManagement registration and the authentication scheme are wired in Program.cs.","Decorate the calling endpoint/controller with [Authorize(Policy = ...)] so failures are handled by the auth middleware (401/403) rather than a thrown exception."],"exampleFix":"// before\nvar authorizationResult = await authorizationService.AuthorizeAsync(user, AuthorizationPolicies.ProductManagement);\nif (!authorizationResult.Succeeded)\n    throw new UnauthorizedAccessException(\"Product management authorization is required.\");\n\n// after (return a 403-friendly result instead of throwing)\nvar authorizationResult = await authorizationService.AuthorizeAsync(user, AuthorizationPolicies.ProductManagement);\nif (!authorizationResult.Succeeded)\n    return Results.Forbid();","handlingStrategy":"validation","validationCode":"var authResult = await authorizationService.AuthorizeAsync(user, AuthorizationPolicies.ProductManagement);\nif (!authResult.Succeeded) return Results.Forbid();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Require [Authorize(Policy = AuthorizationPolicies.ProductManagement)] on the endpoint so the middleware returns 401/403 cleanly.","Verify the policy registration and the authentication scheme are wired in Program.cs.","Ensure tokens carry the role/claim the policy demands."],"tags":["security","authorization","aspnetcore","deployment","grain"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}