Skip to content

Commit aae76ec

Browse files
authored
Custom auth policies with IARD overhaul (#36866)
1 parent b9daff6 commit aae76ec

4 files changed

Lines changed: 196 additions & 21 deletions

File tree

.openpublishing.redirection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1673,6 +1673,11 @@
16731673
"source_path": "aspnetcore/migration/20_21.md",
16741674
"redirect_url": "/aspnet/core/migration/20-to-21",
16751675
"redirect_document_id": false
1676+
},
1677+
{
1678+
"source_path": "aspnetcore/security/authorization/iard.md",
1679+
"redirect_url": "/aspnet/core/security/authorization/custom-authorization-policies-with-iauthorizationrequirementdata",
1680+
"redirect_document_id": false
16761681
}
16771682
]
16781683
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
title: Custom authorization policies with `IAuthorizationRequirementData` in ASP.NET Core MVC
3+
ai-usage: ai-assisted
4+
author: tdykstra
5+
description: Learn how to specify requirements associated with the authorization policy in attribute definitions with the IAuthorizationRequirementData interface in ASP.NET Core MVC.
6+
monikerRange: '>= aspnetcore-8.0'
7+
ms.author: tdykstra
8+
ms.date: 03/11/2026
9+
uid: mvc/security/authorization/iard
10+
---
11+
# Custom authorization policies with `IAuthorizationRequirementData` in ASP.NET Core MVC
12+
13+
This article provides a demonstration on how to use <xref:Microsoft.AspNetCore.Authorization.IAuthorizationRequirementData> to define custom authorization policies in ASP.NET Core MVC. For general guidance on this subject, see <xref:security/authorization/iard>.
14+
15+
## Sample app
16+
17+
The MVC sample for this article is the [`AuthRequirementsData` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/AuthRequirementsData) ([how to download](xref:index#how-to-download-a-sample)). The sample app implements a minimum age handler for users, requiring a user to present a birth date claim indicating that they're at least 21 years old.
18+
19+
## Demonstration
20+
21+
Test the sample with [`dotnet user-jwts`](xref:security/authentication/jwt) and curl.
22+
23+
From the project's folder in a command shell, execute the following command to create a JWT bearer token with a birth date claim that makes the user over 21 years old:
24+
25+
```dotnetcli
26+
dotnet user-jwts create --claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=1989-01-01
27+
```
28+
29+
The output produces a token after "`Token:`" in the command shell:
30+
31+
```dotnetcli
32+
New JWT saved with ID '{JWT ID}'.
33+
Name: {USER}
34+
Custom Claims: [http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=1989-01-01]
35+
36+
Token: {TOKEN}
37+
```
38+
39+
Set the value of the token (where the `{TOKEN}` placeholder appears in the preceding output) aside for use later.
40+
41+
You can decode the token in an online JWT decoder, such as [`jwt.ms`](https://jwt.ms/) to see its contents, revealing that it contains a `birthdate` claim with the user's birth date:
42+
43+
```json
44+
{
45+
"alg": "HS256",
46+
"typ": "JWT"
47+
}.{
48+
"unique_name": "guard",
49+
"sub": "guard",
50+
"jti": "6cd613ed",
51+
"birthdate": "1989-01-01",
52+
"aud": [
53+
"https://localhost:5001",
54+
"http://localhost:5000"
55+
],
56+
"nbf": 1773663513,
57+
"exp": 1781612313,
58+
"iat": 1773663515,
59+
"iss": "dotnet-user-jwts"
60+
}.[Signature]
61+
```
62+
63+
Execute the command again with a `dateofbirth` value that makes the user under the age of 21:
64+
65+
```dotnetcli
66+
dotnet user-jwts create --claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=2020-01-01
67+
```
68+
69+
Set the value of the second token aside.
70+
71+
Start the app in Visual Studio or with the `dotnet watch` command in a command shell:
72+
73+
```dotnetcli
74+
dotnet watch
75+
```
76+
77+
In a command shell, use the .NET CLI to execute the following `curl.exe` command to request the `api/greetings/hello` endpoint. Replace the `{TOKEN}` placeholder with the first JWT bearer token that you saved earlier:
78+
79+
```dotnetcli
80+
curl.exe -i -H "Authorization: Bearer {TOKEN}" https://localhost:5001/api/greetings/hello
81+
```
82+
83+
The output indicates success because the user's birth date claim indicates that they're at least 21 years old:
84+
85+
```dotnetcli
86+
HTTP/1.1 200 OK
87+
Content-Type: text/plain; charset=utf-8
88+
Date: Thu, 15 May 2025 22:58:10 GMT
89+
Server: Kestrel
90+
Transfer-Encoding: chunked
91+
92+
Hello {USER}!
93+
```
94+
95+
Logging indicates that the age requirement was met:
96+
97+
<!-- DOC AUTHOR NOTE
98+
99+
The following block quote uses two spaces at the ends of lines (except the
100+
last line) to create returns in the rendered content. Don't remove the two
101+
spaces at the ends of the lines when editing the following content.
102+
103+
-->
104+
105+
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Evaluating authorization requirement for age >= 21":::
106+
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Minimum age authorization requirement 21 satisfied":::
107+
108+
Re-execute the `curl.exe` command with the second token, which indicates the user is under 21 years old. The output indicates that the requirement isn't met. Access to the endpoint is forbidden (status code 403):
109+
110+
```dotnetcli
111+
HTTP/1.1 403 Forbidden
112+
Content-Length: 0
113+
Date: Thu, 15 May 2025 22:58:36 GMT
114+
Server: Kestrel
115+
```
116+
117+
Logging indicates that the age requirement wasn't met:
118+
119+
<!-- DOC AUTHOR NOTE
120+
121+
The following block quote uses two spaces at the ends of lines (except the
122+
last line) to create returns in the rendered content. Don't remove the two
123+
spaces at the ends of the lines when editing the following content.
124+
125+
-->
126+
127+
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Evaluating authorization requirement for age >= 21":::
128+
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Current user's DateOfBirth claim (2020-01-01) doesn't satisfy the minimum age authorization requirement 21":::

aspnetcore/security/authorization/iard.md renamed to aspnetcore/security/authorization/custom-authorization-policies-with-iauthorizationrequirementdata.md

Lines changed: 61 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
---
22
title: Custom authorization policies with `IAuthorizationRequirementData`
3+
ai-usage: ai-assisted
34
author: tdykstra
45
description: Learn how to specify requirements associated with the authorization policy in attribute definitions with the IAuthorizationRequirementData interface.
5-
ms.author: tdykstra
66
monikerRange: '>= aspnetcore-8.0'
7-
ms.date: 5/16/2025
7+
ms.author: tdykstra
8+
ms.date: 03/11/2026
89
uid: security/authorization/iard
910
---
1011
# Custom authorization policies with `IAuthorizationRequirementData`
1112

1213
Use the <xref:Microsoft.AspNetCore.Authorization.IAuthorizationRequirementData> interface to specify requirements associated with the authorization policy in attribute definitions.
1314

15+
This article uses a [Minimal API](xref:fundamentals/minimal-apis) endpoint within the app and focuses on testing JWT-based authorization. For a demonstration of similar guidance in an MVC app with a controller, see the <xref:mvc/security/authorization/iard>.
16+
1417
## Sample app
1518

16-
The complete sample described in this article is the [AuthRequirementsData sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/AuthRequirementsData) ([how to download](xref:blazor/fundamentals/index#sample-apps)). The sample app implements a minimum age handler for users, requiring a user to present a birth date claim indicating that they're at least 21 years old.
19+
The Blazor Web App sample for this article is the [`AuthRequirementsDataBWA` sample app (`dotnet/AspNetCore.Docs.Samples` GitHub repository)](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/AuthRequirementsDataBWA) ([how to download](xref:index#how-to-download-a-sample)). The sample app implements a minimum age handler for users, requiring a user to present a birth date claim indicating that they're at least 21 years old.
1720

1821
## Minimum age authorize attribute
1922

2023
The `MinimumAgeAuthorizeAttribute` implementation of <xref:Microsoft.AspNetCore.Authorization.IAuthorizationRequirementData> sets an authorization age:
2124

22-
:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgeAuthorizeAttribute.cs":::
25+
:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsDataBWA/Authorization/MinimumAgeAuthorizeAttribute.cs":::
2326

2427
## Minimum age authorization handler
2528

@@ -33,7 +36,7 @@ The `HandleRequirementAsync` method:
3336
* Marks the authorization requirement succeeded if the user meets the age requirement.
3437
* Implements logging for demonstration purposes.
3538

36-
:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Authorization/MinimumAgeAuthorizationHandler.cs":::
39+
:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsDataBWA/Authorization/MinimumAgeAuthorizationHandler.cs":::
3740

3841
The `MinimumAgeAuthorizationHandler` is registered as a singleton <xref:Microsoft.AspNetCore.Authorization.IAuthorizationHandler> service in the app's `Program` file:
3942

@@ -42,26 +45,37 @@ builder.Services.AddSingleton<IAuthorizationHandler,
4245
MinimumAgeAuthorizationHandler>();
4346
```
4447

45-
The `GreetingsController` displays the user's name when they satisfy the minimum age policy, using an age of 21 years old with the `[MinimumAgeAuthorize({AGE})]` attribute, where the `{AGE}` placeholder is the age:
48+
A [Minimal API](xref:fundamentals/minimal-apis) endpoint is configured in the app's `Program` file with the <xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization%2A> extension method and the `MinimumAgeAuthorizeAttribute`:
49+
50+
```csharp
51+
app.MapGet("/api/greetings/hello", (HttpContext context) =>
52+
{
53+
return $"Hello {context.User.Identity?.Name}!";
54+
}).RequireAuthorization(new MinimumAgeAuthorizeAttribute(21));
55+
```
56+
57+
The endpoint displays the user's name when they satisfy the minimum age policy, using an age of 21 years old supplied to a `MinimumAgeAuthorizeAttribute` instance.
4658

47-
:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/AuthRequirementsData/Controllers/GreetingsController.cs":::
59+
If the user's birth date claim indicates that they're at least 21 years old, the endpoint displays the greeting string, issuing a 200 (OK) status code. If the user is missing the birth date claim or the claim indicates that they aren't at least 21 years old, the greeting isn't displayed and a 403 (Forbidden) status code is issued.
4860

49-
If the user's birth date claim indicates that they're at least 21 years old, the controller displays the greeting string, issuing a 200 (OK) status code. If the user is missing the birth date claim or the claim indicates that they aren't at least 21 years old, the greeting isn't displayed and a 403 (Forbidden) status code is issued.
61+
> [!NOTE]
62+
> For MVC controller guidance that demonstrates the same behavior, see <xref:mvc/security/authorization/iard>.
5063
5164
JWT bearer authentication services are added in the app's `Program` file:
5265

5366
```csharp
5467
builder.Services.AddAuthentication().AddJwtBearer();
5568
```
5669

57-
The app settings file (`appsettings.json`) configures the audience and issuer for JWT bearer authentication:
70+
The app settings file (`appsettings.Development.json`) configures the audience and issuer for JWT bearer authentication:
5871

5972
```json
6073
"Authentication": {
6174
"Schemes": {
6275
"Bearer": {
6376
"ValidAudiences": [
64-
"https://localhost:51100"
77+
"https://localhost:5001",
78+
"http://localhost:5000"
6579
],
6680
"ValidIssuer": "dotnet-user-jwts"
6781
}
@@ -100,17 +114,17 @@ You can decode the token in an online JWT decoder, such as [`jwt.ms`](https://jw
100114
"alg": "HS256",
101115
"typ": "JWT"
102116
}.{
103-
"unique_name": "{USER}",
104-
"sub": "{USER}",
105-
"jti": "{JWT ID}",
117+
"unique_name": "guard",
118+
"sub": "guard",
119+
"jti": "6cd613ed",
106120
"birthdate": "1989-01-01",
107121
"aud": [
108-
"https://localhost:51100",
109-
"http://localhost:51101"
122+
"https://localhost:5001",
123+
"http://localhost:5000"
110124
],
111-
"nbf": 1747315312,
112-
"exp": 1755264112,
113-
"iat": 1747315313,
125+
"nbf": 1773663513,
126+
"exp": 1781612313,
127+
"iat": 1773663515,
114128
"iss": "dotnet-user-jwts"
115129
}.[Signature]
116130
```
@@ -123,12 +137,16 @@ dotnet user-jwts create --claim http://schemas.xmlsoap.org/ws/2005/05/identity/c
123137

124138
Set the value of second token aside.
125139

126-
Start the app in Visual Studio or with the `dotnet watch` command in the .NET CLI.
140+
Start the app in Visual Studio or with the `dotnet watch` command in a command shell:
141+
142+
```dotnetcli
143+
dotnet watch
144+
```
127145

128-
In the .NET CLI, execute the following `curl.exe` command to request the `api/greetings/hello` endpoint. Replace the `{TOKEN}` placeholder with the first JWT bearer token that you saved earlier:
146+
In a command shell, use the .NET CLI to execute the following `curl.exe` command to request the `api/greetings/hello` endpoint. Replace the `{TOKEN}` placeholder with the first JWT bearer token that you saved earlier:
129147

130148
```dotnetcli
131-
curl.exe -i -H "Authorization: Bearer {TOKEN}" https://localhost:51100/api/greetings/hello
149+
curl.exe -i -H "Authorization: Bearer {TOKEN}" https://localhost:5001/api/greetings/hello
132150
```
133151

134152
The output indicates success because the user's birth date claim indicates that they're at least 21 years old:
@@ -145,6 +163,14 @@ Hello {USER}!
145163

146164
Logging indicates that the age requirement was met:
147165

166+
<!-- DOC AUTHOR NOTE
167+
168+
The following block quote uses two spaces at the ends of lines (except the
169+
last line) to create returns in the rendered content. Don't remove the two
170+
spaces at the ends of the lines when editing the following content.
171+
172+
-->
173+
148174
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Evaluating authorization requirement for age >= 21":::
149175
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Minimum age authorization requirement 21 satisfied":::
150176
@@ -157,5 +183,19 @@ Date: Thu, 15 May 2025 22:58:36 GMT
157183
Server: Kestrel
158184
```
159185

186+
Logging indicates that the age requirement wasn't met:
187+
188+
<!-- DOC AUTHOR NOTE
189+
190+
The following block quote uses two spaces at the ends of lines (except the
191+
last line) to create returns in the rendered content. Don't remove the two
192+
spaces at the ends of the lines when editing the following content.
193+
194+
-->
195+
160196
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Evaluating authorization requirement for age >= 21":::
161197
> :::no-loc text="MinimumAgeAuthorizationHandler: Information: Current user's DateOfBirth claim (2020-01-01) doesn't satisfy the minimum age authorization requirement 21":::
198+
199+
## Additional resources
200+
201+
<xref:mvc/security/authorization/iard>

aspnetcore/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,8 @@ items:
615615
items:
616616
- name: Simple authorization
617617
uid: mvc/security/authorization/simple
618+
- name: Custom authorization with IAuthorizationRequirementData
619+
uid: mvc/security/authorization/iard
618620
- name: Blazor
619621
items:
620622
- name: Overview

0 commit comments

Comments
 (0)