{"id":18768524,"url":"https://github.com/pdevito3/heimguard","last_synced_at":"2025-05-16T01:06:45.130Z","repository":{"id":65505408,"uuid":"439907290","full_name":"pdevito3/HeimGuard","owner":"pdevito3","description":"🛡 A simple library that allows you to easily manage permissions in your .NET projects.","archived":false,"fork":false,"pushed_at":"2024-12-06T01:44:34.000Z","size":105,"stargazers_count":159,"open_issues_count":0,"forks_count":11,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-16T01:06:38.482Z","etag":null,"topics":["authorization","dotnet","permission","permissions","policy","role","roles","security"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pdevito3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["pdevito3"]}},"created_at":"2021-12-19T16:04:44.000Z","updated_at":"2025-03-07T10:47:47.000Z","dependencies_parsed_at":"2025-04-13T07:52:05.978Z","dependency_job_id":null,"html_url":"https://github.com/pdevito3/HeimGuard","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdevito3%2FHeimGuard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdevito3%2FHeimGuard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdevito3%2FHeimGuard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pdevito3%2FHeimGuard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pdevito3","download_url":"https://codeload.github.com/pdevito3/HeimGuard/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254448579,"owners_count":22072764,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorization","dotnet","permission","permissions","policy","role","roles","security"],"created_at":"2024-11-07T19:13:02.906Z","updated_at":"2025-05-16T01:06:40.123Z","avatar_url":"https://github.com/pdevito3.png","language":"C#","readme":"\u003cp\u003e\n    \u003ca href=\"https://github.com/pdevito3/heimguard/releases\"\u003e\u003cimg src=\"https://img.shields.io/nuget/v/heimguard.svg\" alt=\"Latest Release\"\u003e\u003c/a\u003e   \n    \u003ca href=\"https://github.com/pdevito3/heimguard/blob/master/LICENSE.txt\"\u003e\u003cimg src =\"https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000\" alt=\"License\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## What is HeimGuard?\n\nHeimGuard is a simple library, inspired by [PolicyServer](https://policyserver.io/) and [this talk](https://www.youtube.com/watch?v=Dlrf85NTuAU) by Dominick Baier, that allows you to easily manage permissions in your .NET projects.\n\n\n## Quickstart\n\nThankfully for us, .NET makes it very easy to protect a controller using a specific policy using the `Authorize` attribute, so let's start there:\n\n```csharp\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n\n[ApiController]\n[Route(\"recipes\")]\n[Authorize(Policy = \"RecipesFullAccess\")]\npublic class RecipesController : ControllerBase\n{    \n    [HttpGet]\n    public IActionResult Get()\n    {\n        return Ok();\n    }\n}\n```\n\nNext, I'm going to put my user's role in my `ClaimPrincipal`. This isn't required for HeimGuard to work, but is what we'll use for this example.\n\n```json\t\n{\n  \"sub\": \"145hfy662\",\n  \"name\": \"John Smith\",\n  \"aud\": [\"api1\", \"api2\"],\n  \"role\": [\"Chef\"]\n}\n```\n\nNow I'm going to implement an interface from HeimGuard called `IUserPolicyHandler`. This handler is responsible for implementing your permissions lookup for your user. It should return an `IEnumerable\u003cstring\u003e` that stores all of the permissions that your user has available to them. \n\n**HeimGuard doesn't care how you store permissions and how you access them.** For simplicity sake in the example below, I'm just grabbing a static list, but this could just as easily come from a database or some external administration boundary and could be in whatever shape you want.\n\n```csharp\nusing System.Security.Claims;\nusing HeimGuard;\nusing Services;\n\npublic class Permission \n{\n    public string Name { get; set; }\n    public List\u003cstring\u003e Roles { get; set; }\n}\n\npublic static class DummyPermissionStore\n{\n    public static List\u003cPermission\u003e GetPermissions()\n    {\n        return new List\u003cPermission\u003e()\n        {\n            new()\n            {\n                Name = \"RecipesFullAccess\",\n                Roles = new List\u003cstring\u003e() { \"Chef\" }\n            }\n        };\n    }\n}\n\npublic class SimpleUserPolicyHandler : IUserPolicyHandler\n{\n    private readonly IHttpContextAccessor _httpContextAccessor;\n\n    public UserPolicyHandler(IHttpContextAccessor httpContextAccessor)\n    {\n        _httpContextAccessor = httpContextAccessor;\n    }\n    \n    public async Task\u003cIEnumerable\u003cstring\u003e\u003e GetUserPermissions()\n    {\n        var user = _httpContextAccessor.HttpContext?.User;\n        if (user == null) throw new ArgumentNullException(nameof(user));\n\t\t\t\t\n      \t// this gets the user's role(s) from their ClaimsPrincipal\n        var roles = user.Claims\n          .Where(c =\u003e c.Type == ClaimTypes.Role)\n          .Select(r =\u003e r.Value)\n          .ToArray();\n      \n      \t// this gets their permissions based on their roles. in this example, it's just using a static list\n        var permissions = DummyPermissionStore.GetPermissions()\n            .Where(p =\u003e p.Roles.Any(r =\u003e roles.Contains(r)))\n            .Select(p =\u003e p.Name)\n            .ToArray();\n\n        return await Task.FromResult(permissions.Distinct());\n    }\n}\n```\n\nNow, all we have to do is register our `SimpleUserPolicyHandler` with `AddHeimGuard` and we're good to go:\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    //... other services\n    services.AddHeimGuard\u003cSimpleUserPolicyHandler\u003e()\n      .AutomaticallyCheckPermissions()\n      .MapAuthorizationPolicies();\n}\n```\n\nYou'll notice two other methods extending `AddHeimGuard`. Nether are required, but they do make your life easier. For more details, check out [HeimGuard Enhancements](#heimguard-enhancements).\n\n## Introduction\n\nLet's start by differentiating 3 different levels of permissions:\n\n- **Application access**: these are generally configured in your auth server and passed along in your token (e.g. using audience (`aud`) claim to determine what apis a token can be used in).\n- **Feature access**: permission specific check in a particular application boundary (e.g. can a user perform some action).\n- **Application logic**: custom business logic specific to your application (e.g. given this certain set of criteria, can a user perform some action).\n\nThe goal with HeimGuard is to easily manage user’s permissions around the feature access scope of permissions in your .NET apps using the built in .NET policies you’re familiar with.\n\nOut of the box with .NET, we can easily decorate our controllers like this `[Authorize(Policy = \"RecipesFullAccess\")]` and register it in `AddAuthorization`, but there's a gap here, **how do we check if the user has that claim?**\n\nOne of the most common solutions to this is to load up your policies in your security token.\n\nIdentity is the input to your permissions that, together, determine a user's permissions.\n\n```json\n{\n  \"sub\": \"145hfy662\",\n  \"name\": \"John Smith\",\n  \"aud\": [\"api1\", \"api2\"],\n  \"permission\": [\n    \"ManageRecipe\",\n    \"CreateNewRecipe\",\n    \"UpdateIngredients\"\n  ]\n}\n```\n\nThis can work, but but there are some downsides here:\n\n- Your JWT gets quickly overloaded, potentially to the point of being too big to even put into a cookie. Ideally, your token is only passing along user identity information only.\n- You don't have boundary permission context. Let's look at a couple examples:\n  - As mentioned above, we generally use the `aud` claim (or maybe some custom one) to determine what apis your security token can be used in. So in the example above we have `  \"aud\": [\"api1\", \"api2\"],` and one of my permissions is `ManageRecipe`. What if I am allowed to manage recipes in `api1` but not `api2`? You could prefix them with something like `api1.ManageRecipe`, but that adds coupling, domain logic, and becomes a huge multipler in the amount of claims being passed around.\n  - Say I have a permission `CanDrinkAlcohol` but depending on where I’m at in the world it may or may not be true based on my age. I could tag it with something like `US.CanDrink`, `UK.CanDrink`, etc. but this would be far from ideal for a variety of reasons.\n- Tokens are only given at authentication time, so if you need to update permissions, you need to invalidate all the issued tokens every time you make an update. You could also make token lifetimes very short to get more up to date info more often, but that is not ideal either and still has coupling of identity and permissions.\n\nSo, what do we do? Well we can still get identity state from our identity server like we usually do. Usually, that should include some kind of role or set of roles that the user has been assigned to. These roles can then be mapped to permissions and used as a reference to a group of permissions.\n\n\u003e It’s important to note that these roles should be identity based and make sense across your whole domain, not just a particular boundary. For instance, something like `InventoryManager` would be better than something like `Approver`.\n\nSo we have our user and their identity roles from our auth token, but how do we know what permissions go with our roles? Well, this can be done in a variety of ways to whatever suits your needs best for your api. \n\nIf you have a simple API or an API that rarely has modified permissions, maybe you just want keep a static list of role to permissions mappings in a class in your project or in your appsettings. More commonly, you'll probably want to persist them in a database somewhere. This could be in your boundary/application database or it could be in a separate administration boundary. Maybe you have both and use eventual consistency to keep them in sync. You could even add a caching layer on top of this as well and reference that.\n\nAt the end of the day, you can store your permission to role mappings anywhere you want, but you still need a way to easily access them and integrate them into your permissions pipeline. This is where HeimGuard comes in.\n\n## Getting Started\n\n### Prerequisites\n\nBefore you get HeimGuard set up, make sure that your authorization policies are set up properly. There are two important items here:\n\n1. Add an authorization attribute (e.g. `[Authorize(Policy = \"RecipesFullAccess\")]`) to your controller so HeimGuard knows what policy to check against.\n\n2. Reigster your policy\n\n   ```C#\n   services.AddAuthorization(options =\u003e\n   {\n       options.AddPolicy(\"RecipesFullAccess\",\n           policy =\u003e policy.RequireClaim(\"permission\", \"RecipesFullAccess\"));\n   });\n   ```\n\n\u003e 🎉 Note that #2 isn't required if you are using [MapAuthorizationPolicies](#mapauthorizationpolicies).\n\nSo for this example, let's say we have a controller like so:\n\n```c#\nusing HeimGuard;\nusing Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n\n[ApiController]\n[Route(\"recipes\")]\n[Authorize(Policy = \"RecipesFullAccess\")]\npublic class RecipesController : ControllerBase\n{    \n    [HttpGet]\n    public IActionResult Get()\n    {\n    \treturn Ok()\n    }\n}\n```\n\n\n\n### Setting Up a Permissions Store\n\nTo start out, you're going to set up whatever store you want to use for your roles. This could take pretty much whatever structure you want, the only requirement here is that **a permission must be able to be narrowed down to a string that can be used in our authorization attribute.**\n\nLet's look at a couple different examples of how we might store our permissions.\n\n\u003e 🔮 The examples below are mapping permissions to roles, but this isn't a requirement. You could just as easily associate permissions to users or even apply permissions to users as well as roles.\n\n#### Simple Static Class Store\n\nAs shown in the quickstart, maybe we have a really simple policy that we just want to store in our project. We could just make a `Permission` class that has some roles associated to it and a store to access it. \n\nYou could also make static strings that get used here and throughout your app to prevent spelling issues. Again, lots of flexibility here.\n\n```c#\npublic class Permission \n{\n    public string Name { get; set; }\n    public List\u003cstring\u003e Roles { get; set; }\n}\n\npublic static class SimplePermissionStore\n{\n    public static List\u003cPermission\u003e GetPermissions()\n    {\n        return new List\u003cPermission\u003e()\n        {\n            new()\n            {\n                Name = \"RecipesFullAccess\",\n                Roles = new List\u003cstring\u003e() { \"Chef\" }\n            }\n        };\n    }\n}\n```\n\n#### Database Store\n\nWe could also have some entities that we are storing in our application database or maybe in a separate administration boundary. Notice here how our permissions have a Guid as their key, but we can still get a string out of it using `Name` for our authorization attribute.\n\n```c#\nusing System.ComponentModel.DataAnnotations;\n\npublic class Role\n{\n    [Key]\n    public Guid Id { get; set; }\n    public string Name { get; set; }\n}\n\npublic class Permission\n{\n    [Key]\n    public Guid Id { get; set; }\n    public string Name { get; set; }\n}\n\npublic class RolePermission\n{\n    [Key]\n    public Guid Id { get; set; }\n  \n    [JsonIgnore]\n    [IgnoreDataMember]\n    [ForeignKey(\"Role\")]\n    public Guid RoleId { get; set; }\n    public Role Role { get; set; }\n\n    [JsonIgnore]\n    [IgnoreDataMember]\n    [ForeignKey(\"Permission\")]\n    public Guid PermissionId { get; set; }\n    public Permission Permission { get; set; }\n}\n```\n\n\n\n### Implementing a Policy Handler\n\nNow that we have a store set up, we need to determine how we get our final list of permissions for a given user. \n\nTo do this, we are going to create a class that inherits from HeimGaurd's `IUserPolicyHandler` and implements a method called `GetUserPermissions`. This method will do whatever logic you need to perform to get the permissions for you user. It could do any of, but not limited to the following:\n\n1. Check a static file or database for permissions assigned to a user\n2. Get a user's roles and then reach \n3. ping a database and\n\nAgain, the goal here is to get a list of permissions for my user, particularly as an `IEnumerable\u003cstring\u003e`.\n\n#### Simple Static Class IUserPolicyHandler Example\n\nFor our [Simple Static Class Store](#simple-static-class-store) example above, we have 3 main steps:\n\n1. Get out user from our `ClaimsPrincipal` using `IHttpContextAccessor`. You could inject a `CurrentUserService` or whatever else here to accomplish this.\n2. Get the given roles for that user from their token. Again, these roles could instead be stored in a database or static file as well. You could not even use roles at all and map permissions directly to a user.\n3. Get the permissions assigned to that role from our static list.\n\n```c#\n\npublic class SimpleUserPolicyHandler : IUserPolicyHandler\n{\n    private readonly IHttpContextAccessor _httpContextAccessor;\n\n    public UserPolicyHandler(IHttpContextAccessor httpContextAccessor)\n    {\n        _httpContextAccessor = httpContextAccessor;\n    }\n    \n    public async Task\u003cIEnumerable\u003cstring\u003e\u003e GetUserPermissions()\n    {\n        var user = _httpContextAccessor.HttpContext?.User;\n        if (user == null) throw new ArgumentNullException(nameof(user));\n\t\t\t\t\n      \t// this gets the user's role(s) from their ClaimsPrincipal\n        var roles = user\n          .Claims.Where(c =\u003e c.Type == ClaimTypes.Role)\n          .Select(r =\u003e r.Value)\n          .ToArray();\n      \n      \t// this gets their permissions based on their roles. in this example, it's just using a static list\n        var permissions = SimplePermissionStore.GetPermissions()\n            .Where(p =\u003e p.Roles.Any(r =\u003e roles.Contains(r)))\n            .Select(p =\u003e p.Name)\n            .ToArray();\n\n        return await Task.FromResult(permissions.Distinct());\n    }\n}\n```\n\n#### Database Static Class IUserPolicyHandler Example\n\nFor our [Database Store](#database-store) example above, we have the same 3 steps, just implemented slightly differently to accomodate our database. As a matter of fact, the only difference here is the `var permissions` assignment and injecting my `DbContext`. This is only because I have a similar pattern for both stores, yours could look very different depending on your schema. You could also use a repo, built in method, etc to perform this action and make it more testable.\n\n**However it is implemented, the only thing that matters here is returning a list of strings as your final permissions.**\n\n```c#\npublic class DatabaseUserPolicyHandler : IUserPolicyHandler\n{\n    private readonly RecipesDbContext _dbContext;\n    private readonly IHttpContextAccessor _httpContextAccessor;\n\n    public UserPolicyHandler(RecipesDbContext dbContext, IHttpContextAccessor httpContextAccessor)\n    {\n        _dbContext = dbContext;\n        _httpContextAccessor = httpContextAccessor;\n    }\n    \n    public async Task\u003cIEnumerable\u003cstring\u003e\u003e GetUserPermissions()\n    {\n        var user = _httpContextAccessor.HttpContext?.User;\n        if (user == null) throw new ArgumentNullException(nameof(user));\n\t\t\t\t\n        var roles = user.Claims\n          .Where(c =\u003e c.Type == ClaimTypes.Role)\n          .Select(r =\u003e r.Value)\n          .ToArray();\n      \n        var permissions = await _dbContext.RolePermissions\n            .Where(rp =\u003e roles.Contains(rp.Role.Name))\n            .Select(rp =\u003e rp.Permission.Name)\n            .ToArrayAsync();\n\n        return await Task.FromResult(permissions.Distinct());\n    }\n}\n```\n\n#### Enhancing Your `HasPermission` Checks\n\nThe method `GetUserPermissions()` method requires all permissions for a user to be returned. When using a database, you might want to enhance the permformance of this call. You can do this by having your db use an `Exists` operation. To do this, you can implement the `HasPermission` method on your `UserPolicyHandler`. For example:\n\n```csharp\n\npublic class DatabaseUserPolicyHandler : IUserPolicyHandler\n{\n    private readonly RecipesDbContext _dbContext;\n    private readonly IHttpContextAccessor _httpContextAccessor;\n\n    public UserPolicyHandler(RecipesDbContext dbContext, IHttpContextAccessor httpContextAccessor)\n    {\n        _dbContext = dbContext;\n        _httpContextAccessor = httpContextAccessor;\n    }\n    \n    public async Task\u003cIEnumerable\u003cstring\u003e\u003e GetUserPermissions()\n    {\n        // ...\n    }\n  \n  \tpublic async Task\u003cbool\u003e HasPermission(string permission)\n    {\n        var roles = await GetRoles();\n    \n        // super admins can do everything\n        if (roles.Contains(Role.SuperAdmin().Value))\n            return true;\n        \n        return await _dbContext.RolePermissions\n            .Where(rp =\u003e roles.Contains(rp.Role.Name))\n            .Select(rp =\u003e rp.Permission.Name)\n            .AnyAsync(x =\u003e x == permission);\n    }\n}\n```\n\n\n\n### Registering HeimGuard\n\nOnce you have your `IUserPolicyHandler` implementation set up, just go to your service builder and register HeimGuard like so:\n\n```c#\npublic void ConfigureServices(IServiceCollection services)\n{\n    //...\n    services.AddHeimGuard\u003cSimpleUserPolicyHandler\u003e()\n      .AutomaticallyCheckPermissions()\n      .MapAuthorizationPolicies();\n\t  // OR...\n    services.AddHeimGuard\u003cDatabaseUserPolicyHandler\u003e()\n      .AutomaticallyCheckPermissions()\n      .MapAuthorizationPolicies();\n}\n```\n\nAnd that's it! I've added a couple extension methods on here as they are recommended by default, but they are not required. For more details, check out [HeimGuard Enhancements](#heimguard-enhancements).\n\n## HeimGuard Enhancements\n\nThere are currently two extensions on HeimGuard that are both optional, but depending on your workflow, may save you a lot of manual work.\n\n### AutomaticallyCheckPermissions\n\n- `AutomaticallyCheckPermissions` will automatically checks user permissions when an authorization attribute is used. Again, this is optional, but without this, we would need \n- to add something like this to our controller or service/handler that it calls:\n\n  ```csharp\n  using HeimGuard;\n  using Microsoft.AspNetCore.Authorization;\n  using Microsoft.AspNetCore.Mvc;\n  \n  [ApiController]\n  [Route(\"recipes\")]\n  [Authorize]\n  public class RecipesController : ControllerBase\n  {\n      private readonly IHeimGuardClient _heimGuard;\n  \n      public RecipesController(IHeimGuardClient heimGuard)\n      {\n          _heimGuard = heimGuard;\n      }\n      \n      [HttpGet]\n      public IActionResult Get()\n      {\n          return _heimGuard.HasPermissionAsync(\"RecipesFullAccess\") \n            ? Ok()\n            : Forbidden();\n  \n          // OR...  \n  \n          await _heimGuard.MustHavePermission\u003cForbiddenAccessException\u003e(Permissions.CanAddRecipe);          \n          return Ok();\n      }\n  }\n  ```\n\n### MapAuthorizationPolicies\n\n- `MapAuthorizationPolicies` will automatically map authorization attributes to ASP.NET Core authorization policies that haven't already been mapped. That means you don't have to do something like this for all your policies:\n\n  ```csharp\n  services.AddAuthorization(options =\u003e\n  {\n      options.AddPolicy(\"RecipesFullAccess\",\n          policy =\u003e policy.RequireClaim(\"permission\", \"RecipesFullAccess\"));\n  });\n  ```\n\n\u003e 🧳 Note that if you manually register anything in here it will take presidence over the dynamically added policy.\n\n## Custom Policies\n\nCustom policies can still be written and used as they normally would be in .NET. **Be careful here in that these can get to the grey area of business logic vs authorization.**\n\n* [Microsoft's docs for one requirement](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-6.0#use-a-handler-for-one-requirement)\n* [Microsoft's docs for multiple requirements](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-6.0#use-a-handler-for-multiple-requirements)\n\nGenerally:\n\n1. Write a custom requirement that extends Microsoft's `IAuthorizationRequirement`\n2. Write a handler for that requirement so that any invoked policy that has the custom requirement in it will leverage it.\n   * You can use HeimGuard DI in these handlers to easily check if the given user has the permission at all and then perform your custom requirement checks.\n3. Register that handler in startup\n4. Set up your controller\n\n### ❗️ Important Note\n\nIt's important to note that custom policies can not be automatically resolved with `AutomaticallyCheckPermissions`. That doesn't mean that you have to remove `AutomaticallyCheckPermissions` if you use any custom policies, but you'll need to be deliberate with how you set up your controllers. Sepcifically, you can still add the `Authorize` attribute, but you won't pass it a policy like you normally would. Instead, you'll build the custom requirement and involk your custom handler, which could (and likely should) leverage HeimGuard with DI.\n\n## Tenants\n\nWhen working in a multitenant app, you might end up having different roles across different tenants. For example, say I am an `Admin` in Organization 1, but a `User` in Organization 2. The `Admin` role will likely add a lot of permissions that the user role wouldnt have, but how do we check what organization the user is in for that particular request?\n\nIf your token is configured to have only your current tenant context (e.g. when I logged in my token only got populated with my roles for `Organization 1`, even though I have access ti other organiations), you can grab that claim from your token and use it in your `IUserPolicyHandler` implementation.\n\nMany times this won't be the case though. If you don't know what your tenant context until later in the process, it will generally be easiest to check permissions without using the `Authorize` attribute at all and strictly checking using this method as a stand alone option. Otherwise, you don't have the context to know what tenant you are working with.\n\nFor example, you could add a method to you `IUserPolicyHandler` (or a new service) that can take in a user and get their permissions based on their tenant (i.e. organization).\n\n```c#\npublic bool GetUserPermissionsByTenant(Guid tenantId)\n{\n        var userId = _currentUserService.GetUserId();\n        if (userId == null) throw new ArgumentNullException(nameof(userId));\n\t\t\t\t\n        var roles = _dbContext.UserTenantRoles\n          .Where(utr =\u003e utr.TenantId == tenantId \u0026\u0026 utr.UserId == userId)\n          .Select(utr =\u003e utr.Role.Name)\n          .ToArray();\n      \n        var permissions = await _dbContext.RolePermissions\n            .Where(rp =\u003e roles.Contains(rp.Role.Name))\n            .Select(rp =\u003e rp.Permission.Name)\n            .ToArrayAsync();\n\n        return await Task.FromResult(permissions.Distinct());\n}\n```\n\nThen you could call this inside of your controller or in your CQRS handler.\n\n\u003e 🧢 It's worth noting that at the end of the day, this approach isn't leveraging anything in HeimGuard, so if you need something like this throughout your whole app, then it's probably not even worth bothering with HeimGuard.\n\n## Caching\n\nA potentially downside to this approach of permission mapping is that it can get chatty. If this is causing performance issues for you, one option might be to use a redis cache in your `IUserPolicyHandler` implementation.\n\n## Multiple Policies Per Attribute\n\nWhat if you want to assign multiple policies to a single authorization attribute? At that point, your going to want to build a [custom policy assertion](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) using a function.\n\n```cs\noptions.AddPolicy(\"ThisThingOrThatThing\", policy =\u003e\n    policy.RequireAssertion(context =\u003e\n        context.User.HasClaim(c =\u003e\n            (c.Type == \"ThisThing\" ||\n             c.Type == \"ThatThing\"))));\n```\n\nAlternatively, you can use the just have the `Authorize` attribute on a controller and manually check for permissions in your controller, handler, service, etc. like so.\n```csharp\npublic async Task\u003cRecipeDto\u003e Handle(AddRecipeCommand request, CancellationToken cancellationToken)\n{\n    if(!await _heimGuard.HasPermissionAsync(Permissions.ThisThing) \u0026\u0026 !await _heimGuard.HasPermissionAsync(Permissions.ThisThing))\n        throw new ForbiddenAccessException();\n    \n    var recipe = Recipe.Create(request.RecipeToAdd);\n    await _recipeRepository.Add(recipe, cancellationToken);\n\n    await _unitOfWork.CommitChanges(cancellationToken);\n\n    var recipeAdded = await _recipeRepository.GetById(recipe.Id, cancellationToken: cancellationToken);\n    return _mapper.Map\u003cRecipeDto\u003e(recipeAdded);\n}\n\n```\n\n\n## Example\nCheck out [this example project](https://github.com/pdevito3/HeimGuardExamplePermissions) for one of many options for setting up HeimGuard\n","funding_links":["https://github.com/sponsors/pdevito3"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpdevito3%2Fheimguard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpdevito3%2Fheimguard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpdevito3%2Fheimguard/lists"}