diff --git a/aspnetcore/includes/managed-identities-conn-strings.md b/aspnetcore/includes/managed-identities-conn-strings.md index 688198a40f27..117a5f219fb3 100644 --- a/aspnetcore/includes/managed-identities-conn-strings.md +++ b/aspnetcore/includes/managed-identities-conn-strings.md @@ -1,8 +1,10 @@ --- author: tdykstra ms.author: tdykstra -ms.date: 10/16/2024 +ms.date: 05/14/2026 ms.topic: include --- > [!WARNING] -> This article shows the use of connection strings. When using a local database for development and testing, database user authentication via the connection string isn't required. In production environments, connection strings sometimes include a password to authenticate database access or database operations. A resource owner password credential (ROPC) in a connection string is a security risk to avoid in production apps. Production apps should use the most secure authentication flow available. For more information on authentication for apps deployed to test or production environments, see . +> This article shows the use of connection strings. When a local database is used for development and testing, database user authentication via the connection string isn't required. +> In production environments, connection strings sometimes include a password for authenticating database access or database operations. A resource owner password credential (ROPC) in a connection string is a security risk that should be avoided in production apps. Production apps should use the most secure authentication flow available. +> For more information on authentication for apps deployed to test or production environments, see . diff --git a/aspnetcore/security/authentication/claims.md b/aspnetcore/security/authentication/claims.md index 02d9d05517ab..7ff2994203fc 100644 --- a/aspnetcore/security/authentication/claims.md +++ b/aspnetcore/security/authentication/claims.md @@ -1,36 +1,38 @@ --- -title: Mapping, customizing, and transforming claims in ASP.NET Core +title: Map, customize, transform claims in ASP.NET Core author: damienbod -description: Learn how to map claims, do claims transformations, customize claims. +description: Learn how to map claims, perform claims transformations, and customize claims in ASP.NET Core apps. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett ms.custom: mvc -ms.date: 2/16/2022 +ms.date: 05/15/2026 uid: security/authentication/claims + +# customer intent: As an ASP.NET developer, I want to work with claims in my ASP.NET Core app, so I can map claims, do transformations, and make customizations. --- -# Mapping, customizing, and transforming claims in ASP.NET Core +# Map, customize, and transform claims in ASP.NET Core By [Damien Bowden](https://github.com/damienbod) :::moniker range=">= aspnetcore-6.0" -Claims can be created from any user or identity data which can be issued using a trusted identity provider or ASP.NET Core identity. A claim is a name value pair that represents what the subject is, not what the subject can do. -This article covers the following areas: +Claims can be created from any user or identity data that can be issued by using a trusted identity provider or ASP.NET Core identity. A claim is a name-value pair that represents what the subject is, not what the subject can do. -* How to configure and map claims using an [OpenID Connect](https://openid.net/developers/how-connect-works/) client -* Set the name and role claim +This article describes how to configure and map claims by using an [OpenID Connect](https://openid.net/developers/how-connect-works/) client and covers the following tasks: + +* Set name and role claims * Reset the claims namespaces -* Customize, extend the claims using +* Customize and extend the claims with the method -## Mapping claims using OpenID Connect authentication +## Map claims with OpenID Connect authentication -The profile claims can be returned in the `id_token`, which is returned after a successful authentication. The ASP.NET Core client app only requires the profile scope. When using the `id_token` for claims, no extra claims mapping is required. +The profile claims can be returned in the `id_token`, which is returned after a successful authentication. The ASP.NET Core client app only requires the profile scope. When you use the `id_token` for claims, no extra claims mapping is required. [!code-csharp[](~/security/authentication/claims/sample6/WebRPmapClaims/Program.cs?name=snippet1&highlight=8-26)] The preceding code requires the [Microsoft.AspNetCore.Authentication.OpenIdConnect](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect) NuGet package. -Another way to get the user claims is to use the OpenID Connect User Info API. The ASP.NET Core client app uses the `GetClaimsFromUserInfoEndpoint` property to configure this. One important difference from the first settings, is that you must specify the claims you require using the `MapUniqueJsonKey` method, otherwise only the `name`, `given_name` and `email` standard claims will be available in the client app. The claims included in the `id_token` are mapped per default. This is the major difference to the first option. You must explicitly define some of the claims you require. +Another way to get the user claims is to use the OpenID Connect User Info API. The ASP.NET Core client app uses the `GetClaimsFromUserInfoEndpoint` property to do the configuration. In this scenario, you must explicitly specify the required claims by using the `MapUniqueJsonKey` method. Otherwise, only the `name`, `given_name`, and `email` standard claims are available in the client app. The claims included in the `id_token` are mapped per default. [!code-csharp[](~/security/authentication/claims/sample6/WebRPmapClaims/Program.cs?name=snippet2&highlight=26-29)] @@ -39,11 +41,11 @@ Another way to get the user claims is to use the OpenID Connect User Info API. T :::moniker range="> aspnetcore-8.0" > [!NOTE] -> The default Open ID Connect handler uses Pushed Authorization Requests (PAR) if the identity provider's discovery document advertises support for PAR. The identity provider's discovery document is usually found at `.well-known/openid-configuration`. If you cannot use PAR in the client configuration on the identity provider, PAR can be disabled by using the **PushedAuthorizationBehavior** option. +> The default Open ID Connect handler uses Pushed Authorization Requests (PAR) if the identity provider's discovery document advertises support for PAR. The common location for the identity provider's discovery document is the _.well-known/openid-configuration_ folder. If you can't use PAR in the client configuration on the identity provider, PAR can be disabled by using the `PushedAuthorizationBehavior` option. :::code language="csharp" source="~/release-notes/aspnetcore-9/samples/PAR/Program.cs" id="snippet_1" highlight="8-99"::: -To ensure that authentication only succeeds if PAR is used, use [`PushedAuthorizationBehavior.Require`](xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.PushedAuthorizationBehavior) instead. This change also introduces a new event to which can be used to customize the pushed authorization request or handle it manually. For more information, see the [API proposal](https://github.com/dotnet/aspnetcore/issues/51686). +To ensure authentication succeeds only if PAR is used, use the [PushedAuthorizationBehavior.Require](xref:Microsoft.AspNetCore.Authentication.OpenIdConnect.PushedAuthorizationBehavior) enum instead. This change also introduces a new event to , which can be used to customize the pushed authorization request or handle it manually. For more information, see the [API proposal in GitHub dotnet/aspnetcore issue #51686](https://github.com/dotnet/aspnetcore/issues/51686) - _Support for Pushed Authorization Requests in OidcHandler_. :::moniker-end @@ -51,15 +53,15 @@ To ensure that authentication only succeeds if PAR is used, use [`PushedAuthoriz ## Name claim and role claim mapping -The **Name** claim and the **Role** claim are mapped to default properties in the ASP.NET Core HTTP context. Sometimes it is required to use different claims for the default properties, or the name claim and the role claim do not match the default values. The claims can be mapped using the **TokenValidationParameters** property and set to any claim as required. The values from the claims can be used directly in the HttpContext **User.Identity.Name** property and the roles. +The **name** claim and **role** claim are mapped to default properties in the ASP.NET Core HTTP context. Sometimes, you need to use different claims for the default properties, or the name claim and role claim don't match the default values. The claims can be mapped by using the `TokenValidationParameters` property and set to any claim as required. The values from the claims can be used directly in the HttpContext `User.Identity.Name` property and the roles. -If the `User.Identity.Name` has no value or the roles are missing, please check the values in the returned claims and set the `NameClaimType` and the `RoleClaimType` values. The returned claims from the client authentication can be viewed in the HTTP context. +If the `User.Identity.Name` property has no value, or the roles are missing, check the values in the returned claims and set the `NameClaimType` and the `RoleClaimType` values. The returned claims from the client authentication can be viewed in the HTTP context. [!code-csharp[](~/security/authentication/claims/sample6/WebRPmapClaims/Program.cs?name=snippet_name&highlight=10-14)] ## Claims namespaces, default namespaces -ASP.NET Core adds default namespaces to some known claims, which might not be required in the app. Optionally, disable these added namespaces and use the exact claims that the OpenID Connect server created. +ASP.NET Core adds default namespaces to some known claims. The default claims might not be required in the app. As an option, you can disable the added namespaces and use the exact claims that the OpenID Connect server created. :::moniker-end @@ -68,7 +70,6 @@ ASP.NET Core adds default namespaces to some known claims, which might not be re [!code-csharp[](~/security/authentication/claims/sample8/WebRPmapClaims/Program.cs?name=snippet_NS&highlight=5)] :::moniker-end - :::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0" [!code-csharp[](~/security/authentication/claims/sample6/WebRPmapClaims/Program.cs?name=snippet_NS&highlight=5)] @@ -77,13 +78,13 @@ ASP.NET Core adds default namespaces to some known claims, which might not be re :::moniker range=">= aspnetcore-6.0" -If you need to disable the namespaces per scheme and not globally, you can use the **MapInboundClaims = false** option. +If you need to disable the namespaces per scheme and not globally, you can use the `MapInboundClaims = false` option. [!code-csharp[](~/security/authentication/claims/sample8/WebRPmapClaims/Program.cs?name=snippet_NS8&highlight=20)] -## Extend or add custom claims using `IClaimsTransformation` +## Extend or add custom claims using 'IClaimsTransformation' -The interface can be used to add extra claims to the class. The interface requires a single method . This method might get called multiple times. Only add a new claim if it does not already exist in the `ClaimsPrincipal`. A `ClaimsIdentity` is created to add the new claims and this can be added to the `ClaimsPrincipal`. +The interface can be used to add extra claims to the class. The interface requires a single method, . This method might be called multiple times. Only add a new claim if it doesn't already exist in the `ClaimsPrincipal`. A `ClaimsIdentity` object is created to add the new claims and it can be added to the `ClaimsPrincipal`. [!code-csharp[](~/security/authentication/claims/sample6/WebRPmapClaims/MyClaimsTransformation.cs)] @@ -103,13 +104,10 @@ Refer to the following document: ## Map claims from external identity providers -Refer to the following document: - -[Persist additional claims and tokens from external providers in ASP.NET Core](xref:security/authentication/social/additional-claims) +If you want to map claims from external identity providers for your app, see [Persist other claims and tokens from external providers in ASP.NET Core](xref:security/authentication/social/additional-claims). :::moniker-end - :::moniker range="< aspnetcore-6.0" Claims can be created from any user or identity data which can be issued using a trusted identity provider or ASP.NET Core identity. A claim is a name value pair that represents what the subject is, not what the subject can do. @@ -254,3 +252,8 @@ Refer to the following document: [Persist additional claims and tokens from external providers in ASP.NET Core](xref:security/authentication/social/additional-claims) :::moniker-end + +## Related content + +- +- diff --git a/aspnetcore/security/authentication/identity-enable-qrcodes.md b/aspnetcore/security/authentication/identity-enable-qrcodes.md index 08f8cc3ff3e2..597f8931f448 100644 --- a/aspnetcore/security/authentication/identity-enable-qrcodes.md +++ b/aspnetcore/security/authentication/identity-enable-qrcodes.md @@ -1,92 +1,93 @@ --- -title: Enable QR code generation for TOTP authenticator apps in ASP.NET Core +title: Enable QR code generation for TOTP authentication ai-usage: ai-assisted author: wadepickett -description: Discover how to enable QR code generation for TOTP authenticator apps that work with ASP.NET Core two-factor authentication. +description: Discover how to enable QR code generation for time-based one-time password (TOTP) authenticator apps that work with ASP.NET Core two-factor authentication. monikerRange: '>= aspnetcore-2.1' ms.author: wpickett -ms.date: 04/21/2026 +ms.date: 05/15/2026 ms.reviewer: wpickett uid: security/authentication/identity-enable-qrcodes + +# customer intent: As an ASP.NET developer, I want to enable QR code generation for TOTP authenticator apps, so I can support two-factor authentication. --- # Enable QR code generation for TOTP authenticator apps in ASP.NET Core -ASP.NET Core includes support for authenticator applications for individual authentication: - -- Two-factor authentication (2FA) authenticator apps use a Time-based One-time Password Algorithm (TOTP), the industry-recommended approach for 2FA. -- TOTP-based 2FA is preferred over SMS 2FA. -- An authenticator app provides a 6 to 8 digit code that users enter after confirming their username and password. -- Typically, users install an authenticator app on a smartphone. +ASP.NET Core includes support for authenticator applications for user authentication. Two-factor authentication (2FA) authenticator apps use a Time-based One-time Password Algorithm (TOTP), the industry-recommended approach for 2FA. (TOTP-based 2FA is preferred over SMS 2FA.) Users typically install the authenticator app on a smartphone. The app provides a 6 to 8 digit code that the user enters after they confirm their username and password. > [!WARNING] -> Keep an ASP.NET Core TOTP code secret because it can be used to authenticate successfully multiple times before it expires. +> Keep the ASP.NET Core TOTP code secret. The user can enter the code multiple times and authenticate successfully before it expires. :::moniker range=">= aspnetcore-8.0" -The ASP.NET Core web app templates support authenticators but don't provide support for QR code generation. QR code generators make it easier to set up 2FA. This article provides guidance for Razor Pages and MVC apps on how to add [QR code](https://wikipedia.org/wiki/QR_code) generation to the 2FA configuration page. For guidance that applies to Blazor Web Apps, see . For guidance that applies to Blazor WebAssembly apps, see . +The ASP.NET Core web app templates support authenticators, but they don't provide support for QR code generation. QR code generators make it easier to set up 2FA. This article provides guidance for Razor Pages and MVC apps on how to add [QR code](https://wikipedia.org/wiki/QR_code) generation to the 2FA configuration page. :::moniker-end - :::moniker range="< aspnetcore-8.0" The ASP.NET Core web app templates support authenticators but don't provide support for QR code generation. QR code generators make it easier to set up 2FA. This article guides you through adding [QR code](https://wikipedia.org/wiki/QR_code) generation to the 2FA configuration page. -> [!NOTE] -> For ASP.NET Core 8.0 or later, Blazor-specific guidance for QR code generation is available for (Blazor Web App) and (Blazor WebAssembly with Identity). - :::moniker-end -Two-factor authentication doesn't happen by using an external authentication provider, such as [Google](xref:security/authentication/google-logins) or [Facebook](xref:security/authentication/facebook-logins). External logins are protected by whatever mechanism the external login provider provides. For example, the [Microsoft](xref:security/authentication/microsoft-logins) authentication provider requires a hardware key or another 2FA approach. If the default templates required 2FA for both the web app and the external authentication provider, users would need to satisfy two 2FA approaches. Requiring two 2FA approaches deviates from established security practices, which typically rely on a single, strong 2FA method for authentication. +Two-factor authentication doesn't happen by using an external authentication provider, such as [Google](xref:security/authentication/google-logins) or [Facebook](xref:security/authentication/facebook-logins). External sign ins are protected by whatever mechanism the external authentication provider supports. For example, the [Microsoft](xref:security/authentication/microsoft-logins) authentication provider requires a hardware key or another 2FA approach. When the default templates require 2FA for both the web app and the external authentication provider, users need to satisfy two 2FA approaches. Requiring two 2FA approaches deviates from established security practices, which typically rely on a single, strong 2FA method for authentication. -## Adding QR codes to the 2FA configuration page +If you're working with Blazor in ASP.NET Core 8.0 or later, you can find similar guidance in the following articles: -These instructions use `qrcode.js` from the [https://davidshimjs.github.io/qrcodejs/](https://davidshimjs.github.io/qrcodejs/) repo. +* +* -* Download the [`qrcode.js` JavaScript library](https://davidshimjs.github.io/qrcodejs/) to the `wwwroot\lib` folder in your project. -* Follow the instructions in [Scaffold Identity](xref:security/authentication/scaffold-identity) to generate `/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml`. -* In `/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml`, locate the `Scripts` section at the end of the file: +## Add QR codes to the 2FA configuration page -```cshtml -@section Scripts { - -} -``` -* Create a new JavaScript file called `qr.js` in `wwwroot/js` and add the following code to generate the QR code: - -```javascript -window.addEventListener("load", () => { - const uri = document.getElementById("qrCodeData").getAttribute('data-url'); - new QRCode(document.getElementById("qrCode"), - { - text: uri, - width: 150, - height: 150 - }); -}); -``` +The following instructions use the _qrcode.js_ file from the [https://davidshimjs.github.io/qrcodejs/](https://davidshimjs.github.io/qrcodejs/) repo. -* Update the `Scripts` section to add a reference to the `qrcode.js` library you previously downloaded. -* Add the `qr.js` file with the call to generate the QR code: +1. Download the ['qrcode.js' JavaScript library](https://davidshimjs.github.io/qrcodejs/) to the _wwwroot\lib_ folder in your project. -```cshtml -@section Scripts { - +1. Follow the instructions in [Scaffold Identity](xref:security/authentication/scaffold-identity) to generate the _/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml_ file. - - -} -``` +1. In the _/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml_ file, locate the `Scripts` section at the end of the file: -* Delete the paragraph that links you to these instructions. + ```cshtml + @section Scripts { + + } + ``` -Run your app and ensure that you can scan the QR code and validate the code the authenticator provides. +1. Create a new JavaScript file named _qr.js_ in the _wwwroot/js_ folder, and add the following code that generates the QR code: + + ```javascript + window.addEventListener("load", () => { + const uri = document.getElementById("qrCodeData").getAttribute('data-url'); + new QRCode(document.getElementById("qrCode"), + { + text: uri, + width: 150, + height: 150 + }); + }); + ``` + +1. Update the `Scripts` section to add a reference to the `qrcode.js` library you previously downloaded. + +1. Add the _qr.js_ file with the call that generates the QR code: + + ```cshtml + @section Scripts { + + + + } + ``` + +1. Delete the paragraph that links you to these instructions. + +1. Run your app. Confirm you can scan the QR code and validate the code the authenticator provides. ## Change the site name in the QR code -The site name in the QR code comes from the project name you choose when initially creating your project. You can change it by looking for the `GenerateQrCodeUri(string email, string unformattedKey)` method in the `/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs`. +The site name in the QR code comes from the project name you select when you create your project. You can change it by looking for the `GenerateQrCodeUri(string email, string unformattedKey)` method in the _/Areas/Identity/Pages/Account/Manage/EnableAuthenticator.cshtml.cs_ file. -The default code from the template looks as follows: +Here's the default code from the template: ```csharp private string GenerateQrCodeUri(string email, string unformattedKey) @@ -99,17 +100,22 @@ private string GenerateQrCodeUri(string email, string unformattedKey) } ``` -The second parameter in the call to `string.Format` is your site name, taken from your solution name. You can change it to any value, but it must always be URL encoded. +The second parameter in the call to `string.Format` is your site name, which is obtained from your solution name. You can change it to any value, but it must always be URL encoded. -## Using a different QR code library +## Use a different QR code library You can replace the QR code library with your preferred library. The HTML contains a `qrCode` element into which you can place a QR code by whatever mechanism your library provides. -You can find the correctly formatted URL for the QR code in the: +You can find the correctly formatted URL for the QR code in the following locations: + +* `AuthenticatorUri` property of the model +* `data-url` property in the `qrCodeData` element + +## Check TOTP client and server times -* `AuthenticatorUri` property of the model. -* `data-url` property in the `qrCodeData` element. +TOTP (Time-based One-Time Password) authentication depends on both the server and authenticator device having an accurate time. Tokens only last for 30 seconds. If TOTP 2FA sign-in fails, confirm the server time is accurate, and preferably synchronized to an accurate NTP service. -## TOTP client and server time skew +## Related content -TOTP (Time-based One-Time Password) authentication depends on both the server and authenticator device having an accurate time. Tokens only last for 30 seconds. If TOTP 2FA logins fail, check that the server time is accurate, and preferably synchronized to an accurate NTP service. +- +- diff --git a/aspnetcore/security/authentication/mfa.md b/aspnetcore/security/authentication/mfa.md index 03ecb54812b5..e9eeda5bcc62 100644 --- a/aspnetcore/security/authentication/mfa.md +++ b/aspnetcore/security/authentication/mfa.md @@ -1,15 +1,17 @@ --- -title: Multi-factor authentication in ASP.NET Core +title: Multifactor authentication in ASP.NET Core author: damienbod -description: Learn how to set up multi-factor authentication (MFA) in an ASP.NET Core app. +description: Learn how to set up multifactor authentication (MFA) in an ASP.NET Core app. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett ms.custom: mvc -ms.date: 10/29/2024 +ms.date: 05/15/2026 uid: security/authentication/mfa + +# customer intent: As an ASP.NET developer, I want to set up multifactor authentication in ASP.NET Core, so I can control user access to my app. --- -# Multi-factor authentication in ASP.NET Core +# Multifactor authentication in ASP.NET Core [!INCLUDE[](~/includes/not-latest-version.md)] @@ -17,64 +19,63 @@ uid: security/authentication/mfa By [Damien Bowden](https://github.com/damienbod) -[View or download sample code (damienbod/AspNetCoreHybridFlowWithApi GitHub repository)](https://github.com/damienbod/AspNetCoreHybridFlowWithApi) +Multifactor authentication (MFA) is a process in which a user is requested during sign in for more forms of identification. The prompt might request the user to enter a code from a cellphone, use an FIDO2 key, or provide a fingerprint scan. When you require a second form of authentication, security is enhanced. The extra factor isn't easily obtained or duplicated by a cyberattacker. -Multi-factor authentication (MFA) is a process in which a user is requested during a sign-in event for additional forms of identification. This prompt could be to enter a code from a cellphone, use a FIDO2 key, or to provide a fingerprint scan. When you require a second form of authentication, security is enhanced. The additional factor isn't easily obtained or duplicated by a cyberattacker. +This article provides an overview of multifactor authentication in ASP.NET Core and the recommended authentication flows with examples that show how to: -This article covers the following areas: +* Configure MFA for administration pages by using ASP.NET Core Identity. +* Send an MFA sign-in requirement to the OpenID Connect server. +* Force the ASP.NET Core OpenID Connect client to require MFA. -* What is MFA and what MFA flows are recommended -* Configure MFA for administration pages using ASP.NET Core Identity -* Send MFA sign-in requirement to OpenID Connect server -* Force ASP.NET Core OpenID Connect client to require MFA +[View or download the sample code](https://github.com/damienbod/AspNetCoreHybridFlowWithApi) ([how to download](xref:fundamentals/index#how-to-download-a-sample)). -## MFA, 2FA +## MFA versus 2FA -MFA requires at least two or more types of proof for an identity like something you know, something you possess, or biometric validation for the user to authenticate. +MFA requires at least two or more types of proof for an identity. Proof types can be something you know, something you possess, or biometric validation for the user to authenticate. -Two-factor authentication (2FA) is like a subset of MFA, but the difference being that MFA can require two or more factors to prove the identity. +Two-factor authentication (2FA) is like a subset of MFA. 2FA requires exactly two types of proof, whereas MFA can require two or _more_ factors to prove the identity. 2FA is supported by default when using ASP.NET Core Identity. To enable or disable 2FA for a specific user, set the property. The ASP.NET Core Identity Default UI includes pages for configuring 2FA. ### MFA TOTP (Time-based One-time Password Algorithm) -MFA using TOTP is supported by default when using ASP.NET Core Identity. This approach can be used together with any compliant authenticator app, including: +MFA with TOTP is supported by default when using ASP.NET Core Identity. This approach can be used together with any compliant authenticator app, including: * Microsoft Authenticator * Google Authenticator For implementation details, see [Enable QR Code generation for TOTP authenticator apps in ASP.NET Core](xref:security/authentication/identity-enable-qrcodes). -To disable support for MFA TOTP, configure authentication using instead of . `AddDefaultIdentity` calls internally, which registers multiple token providers including one for MFA TOTP. To register only specific token providers, call for each required provider. For more information on available token providers, see the [`AddDefaultTokenProviders` reference source (`dotnet/aspnetcore` GitHub repository)](https://github.com/dotnet/aspnetcore/blob/main/src/Identity/Core/src/IdentityBuilderExtensions.cs). +To disable support for MFA TOTP, configure authentication by using the method instead of the method. The `AddDefaultIdentity` method calls the method internally, which registers multiple token providers including one for MFA TOTP. To register only specific token providers, call the method for each required provider. For more information on available token providers, see the ['AddDefaultTokenProviders' reference source](https://github.com/dotnet/aspnetcore/blob/main/src/Identity/Core/src/IdentityBuilderExtensions.cs) in the `dotnet/aspnetcore` GitHub repository. [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] ### MFA passkeys/FIDO2 or passwordless -passkeys/FIDO2 is currently: +The **passkeys/FIDO2** approach is currently: -* The most secure way of achieving MFA. -* MFA that protects against phishing attacks. (As well as certificate authentication and Windows for business) +* The most secure way to achieve MFA. +* MFA that protects against phishing attacks (also certificate authentication and Windows for business). -ASP.NET Core supports passkeys using ASP.NET Core Identity. Passkeys/FIDO2 can be used for MFA or passwordless flows. For more information, see . +ASP.NET Core supports passkeys by using ASP.NET Core Identity. Passkeys/FIDO2 can be used for MFA or passwordless flows. For more information, see . -Microsoft Entra ID provides support for passkeys/FIDO2 and passwordless flows. For more information, see [Passwordless authentication options](/azure/active-directory/authentication/concept-authentication-passwordless). +Microsoft Entra ID provides support for passkeys/FIDO2 and passwordless flows. For more information, see [Authentication methods in Microsoft Entra ID - passkeys (FIDO2)](/entra/identity/authentication/concept-authentication-passkeys-fido2). -Other forms of passwordless MFA do not or may not protect against phishing. +Other forms of passwordless MFA either don't or might not protect against phishing. ### MFA SMS MFA with SMS increases security massively compared with password authentication (single factor). However, using SMS as a second factor is no longer recommended. Too many known attack vectors exist for this type of implementation. -[NIST guidelines](https://pages.nist.gov/800-63-3/sp800-63b.html) +For more information, see the [NIST Digital Identity Guidelines (Special Publication 800-63B)](https://pages.nist.gov/800-63-3/sp800-63b.html). -## Configure MFA for administration pages using ASP.NET Core Identity +## Configure MFA for administration pages with ASP.NET Core Identity -MFA could be forced on users to access sensitive pages within an ASP.NET Core Identity app. This could be useful for apps where different levels of access exist for the different identities. For example, users might be able to view the profile data using a password login, but an administrator would be required to use MFA to access the administrative pages. +You can force MFA on users to enable access to sensitive pages within an ASP.NET Core Identity app. This approach can be useful for apps where different levels of access exist for different identities. For example, users might be able to view the profile data by using a password sign-in process, but an administrator would be required to use MFA to access the administrative pages. -### Extend the login with an MFA claim +### Extend the sign-in process with an MFA claim -The demo code is setup using ASP.NET Core with Identity and Razor Pages. The `AddIdentity` method is used instead of `AddDefaultIdentity` one, so an `IUserClaimsPrincipalFactory` implementation can be used to add claims to the identity after a successful login. +The example code configuration uses ASP.NET Core with Identity and Razor Pages. The `AddIdentity` method is used instead of `AddDefaultIdentity`, so an `IUserClaimsPrincipalFactory` implementation can be used to add claims to the identity after successful sign in. [!INCLUDE [managed-identities](~/includes/managed-identities-conn-strings.md)] @@ -98,7 +99,7 @@ builder.Services.AddAuthorization(options => builder.Services.AddRazorPages(); ``` -The `AdditionalUserClaimsPrincipalFactory` class adds the `amr` claim to the user claims only after a successful login. The claim's value is read from the database. The claim is added here because the user should only access the higher protected view if the identity has logged in with MFA. If the database view is read from the database directly instead of using the claim, it's possible to access the view without MFA directly after activating the MFA. +The `AdditionalUserClaimsPrincipalFactory` class adds the `amr` claim (Authentication Methods References claim) to the user claims only after a successful sign in. The claim value is read from the database. The claim is added here because the user should only access the higher protected view if the identity is signed in with MFA. If the database view is read from the database directly instead of using the claim, it's possible to access the view without MFA directly after activating the MFA. ```csharp using Microsoft.AspNetCore.Identity; @@ -143,25 +144,28 @@ namespace IdentityStandaloneMfa } ``` -Because the Identity service setup changed in the `Startup` class, the layouts of the Identity need to be updated. Scaffold the Identity pages into the app. Define the layout in the `Identity/Account/Manage/_Layout.cshtml` file. +Because the Identity service setup changed in the `Startup` class, the layouts of the Identity need to be updated: -```cshtml -@{ - Layout = "/Pages/Shared/_Layout.cshtml"; -} -``` +* Scaffold the Identity pages into the app. +* Define the layout in the _Identity/Account/Manage/\_Layout.cshtml_ file. -Also assign the layout for all the manage pages from the Identity pages: + ```cshtml + @{ + Layout = "/Pages/Shared/_Layout.cshtml"; + } + ``` -```cshtml -@{ - Layout = "_Layout.cshtml"; -} -``` +* Also, assign the layout for all the manage pages from the Identity pages: + + ```cshtml + @{ + Layout = "_Layout.cshtml"; + } + ``` ### Validate the MFA requirement in the administration page -The administration Razor Page validates that the user has logged in using MFA. In the `OnGet` method, the identity is used to access the user claims. The `amr` claim is checked for the value `mfa`. If the identity is missing this claim or is `false`, the page redirects to the Enable MFA page. This is possible because the user has logged in already, but without MFA. +The administration Razor Page validates that the user is signed in via MFA. In the `OnGet` method, the identity is used to access the user claims. The `amr` claim is checked for the value `mfa`. If the identity is missing this claim or is `false`, the page redirects to the Enable MFA page. This action is possible because the user is already signed in, but without MFA. ```csharp using System; @@ -197,9 +201,9 @@ namespace IdentityStandaloneMfa } ``` -### UI logic to toggle user login information +### UI logic to toggle user sign-in information -An authorization policy was added at startup. The policy requires the `amr` claim with the value `mfa`. +An authorization policy was added at startup. The policy requires the `amr` claim with the value `mfa`: ```csharp services.AddAuthorization(options => @@ -217,7 +221,9 @@ This policy can then be used in the `_Layout` view to show or hide the **Admin** @inject IAuthorizationService AuthorizationService ``` -If the identity has logged in using MFA, the **Admin** menu is displayed without the tooltip warning. When the user has logged in without MFA, the **Admin (Not Enabled)** menu is displayed along with the tooltip that informs the user (explaining the warning). +If the identity is signed in via MFA, the **Admin** menu displays without the tooltip warning. + +When the user is signed in without MFA, the **Admin (Not Enabled)** menu displays along with the tooltip that informs the user (explaining the warning). ```cshtml @if (SignInManager.IsSignedIn(User)) @@ -243,26 +249,26 @@ If the identity has logged in using MFA, the **Admin** menu is displayed without } ``` -If the user logs in without MFA, the warning is displayed: +If the user signs in without MFA, the **Admin** option shows the **(Not Enabled)** warning: -![Administrator MFA authentication](~/security/authentication/mfa/_static/identitystandalonemfa_01.png) +:::image type="content" source="~/security/authentication/mfa/_static/identitystandalonemfa_01.png" alt-text="Screenshot showing the user signed in without MFA authentication, and the 'Not Enabled' warning on the Admin option."::: -The user is redirected to the MFA enable view when clicking the **Admin** link: +When the user selects the **Admin** option, they're redirected to a view where they can enable MFA: -![Administrator activates MFA authentication](~/security/authentication/mfa/_static/identitystandalonemfa_02.png) +:::image type="content" source="~/security/authentication/mfa/_static/identitystandalonemfa_02.png" alt-text="Screenshot showing the 'Manage your account' view where the user can enable MFA authentication as an administrator."::: ## Send MFA sign-in requirement to OpenID Connect server The `acr_values` parameter can be used to pass the `mfa` required value from the client to the server in an authentication request. > [!NOTE] -> The `acr_values` parameter needs to be handled on the OpenID Connect server for this to work. +> The `acr_values` parameter needs to be handled on the OpenID Connect server for this approach to work. ### OpenID Connect ASP.NET Core client -The ASP.NET Core Razor Pages OpenID Connect client app uses the `AddOpenIdConnect` method to login to the OpenID Connect server. The `acr_values` parameter is set with the `mfa` value and sent with the authentication request. The `OpenIdConnectEvents` is used to add this. +The ASP.NET Core Razor Pages OpenID Connect client app uses the `AddOpenIdConnect` method to sign into the OpenID Connect server. The `acr_values` parameter is set with the `mfa` value and sent with the authentication request. The `OpenIdConnectEvents` is used to add this value. -For recommended `acr_values` parameter values, see [Authentication Method Reference Values](https://tools.ietf.org/html/draft-ietf-oauth-amr-values-08). +For recommended `acr_values` parameter values, see the [IETF Authentication Method Reference Values](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-amr-values-08) specification. ```csharp build.Services.AddAuthentication(options => @@ -290,11 +296,13 @@ build.Services.AddAuthentication(options => }); ``` -### Example OpenID Connect Duende IdentityServer server with ASP.NET Core Identity +### Example: OpenID Connect Duende IdentityServer server + +The following example demonstrates OpenID Connect Duende IdentityServer server with ASP.NET Core Identity. On the OpenID Connect server, which is implemented by using ASP.NET Core Identity with Razor Pages, a new page named `ErrorEnable2FA.cshtml` is created. -On the OpenID Connect server, which is implemented using ASP.NET Core Identity with Razor Pages, a new page named `ErrorEnable2FA.cshtml` is created. The view: +The page view: -* Displays if the Identity comes from an app that requires MFA but the user hasn't activated this in Identity. +* Displays if the Identity comes from an app that requires MFA, but the user hasn't activated MFA in Identity. * Informs the user and adds a link to activate this. ```cshtml @@ -313,11 +321,11 @@ You can enable MFA to login here: Enable MFA ``` -In the `Login` method, the `IIdentityServerInteractionService` interface implementation `_interaction` is used to access the OpenID Connect request parameters. The `acr_values` parameter is accessed using the `AcrValues` property. As the client sent this with `mfa` set, this can then be checked. +In the `Login` method, the `IIdentityServerInteractionService` interface implementation `_interaction` is used to access the OpenID Connect request parameters. The `acr_values` parameter is accessed by using the `AcrValues` property. Because the client sent this with `mfa` set, this can then be checked. -If MFA is required, and the user in ASP.NET Core Identity has MFA enabled, then the login continues. When the user has no MFA enabled, the user is redirected to the custom view `ErrorEnable2FA.cshtml`. Then ASP.NET Core Identity signs the user in. +If MFA is required, and the user in ASP.NET Core Identity is enabled with MFA, the sign-in process continues. When the user has no MFA enabled, the user is redirected to the custom view `ErrorEnable2FA.cshtml`. Then ASP.NET Core Identity signs the user in. -The Fido2Store is used to check if the user has activated MFA using a custom FIDO2 Token Provider. +The Fido2Store is used to check if the user activated MFA by using a custom FIDO2 Token Provider. ```csharp public async Task OnPost() @@ -363,19 +371,18 @@ public async Task OnPost() } ``` - -If the user is already logged in, the client app: +If the user is already signed in, the client app: * Still validates the `amr` claim. -* Can set up the MFA with a link to the ASP.NET Core Identity view. +* Can set up the MFA with a link to the ASP.NET Core Identity view, such as **Enable MFA**: -![acr_values-1 image](~/security/authentication/mfa/_static/acr_values-1.png) + :::image type="content" source="~/security/authentication/mfa/_static/acr_values-1.png" alt-text="Screenshot showing the client requires sign in with multifactor authentication and the 'Enable MFA' option."::: ## Force ASP.NET Core OpenID Connect client to require MFA -This example shows how an ASP.NET Core Razor Page app, which uses OpenID Connect to sign in, can require that users have authenticated using MFA. +This example shows how an ASP.NET Core Razor Page app, which uses OpenID Connect to sign in, can require users are authenticated by using MFA. -To validate the MFA requirement, an `IAuthorizationRequirement` requirement is created. This will be added to the pages using a policy that requires MFA. +To validate the MFA requirement, an `IAuthorizationRequirement` requirement is created. The requirement is added to the pages by using a policy that requires MFA. ```csharp using Microsoft.AspNetCore.Authorization; @@ -386,11 +393,11 @@ public class RequireMfa : IAuthorizationRequirement{} ``` -An `AuthorizationHandler` is implemented that will use the `amr` claim and check for the value `mfa`. The `amr` is returned in the `id_token` of a successful authentication and can have many different values as defined in the [Authentication Method Reference Values](https://tools.ietf.org/html/draft-ietf-oauth-amr-values-08) specification. +An `AuthorizationHandler` is implemented to use the `amr` claim and check for the value `mfa`. The `amr` is returned in the `id_token` of a successful authentication and can have many different values, as defined in the [IETF Authentication Method Reference Values](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-amr-values-08) specification. The returned value depends on how the identity authenticated and on the OpenID Connect server implementation. -The `AuthorizationHandler` uses the `RequireMfa` requirement and validates the `amr` claim. The OpenID Connect server can be implemented using Duende Identity Server with ASP.NET Core Identity. When a user logs in using TOTP, the `amr` claim is returned with an MFA value. If using a different OpenID Connect server implementation or a different MFA type, the `amr` claim will, or can, have a different value. The code must be extended to accept this as well. +The `AuthorizationHandler` uses the `RequireMfa` requirement and validates the `amr` claim. The OpenID Connect server can be implemented by using Duende Identity Server with ASP.NET Core Identity. When a user signs in by using TOTP, the `amr` claim is returned with an MFA value. If you use a different OpenID Connect server implementation or a different MFA type, the `amr` claim can have a different value. The code must be extended to accept the other possible values. ```csharp public class RequireMfaHandler : AuthorizationHandler @@ -460,7 +467,7 @@ builder.Services.AddAuthorization(options => builder.Services.AddRazorPages(); ``` -This policy is then used in the Razor page as required. The policy could be added globally for the entire app as well. +The policy is then used in the Razor page as required. The policy can also be added globally for the entire app. ```csharp [Authorize(Policy= "RequireMfa")] @@ -472,7 +479,7 @@ public class IndexModel : PageModel } ``` -If the user authenticates without MFA, the `amr` claim will probably have a `pwd` value. The request won't be authorized to access the page. Using the default values, the user will be redirected to the *Account/AccessDenied* page. This behavior can be changed or you can implement your own custom logic here. In this example, a link is added so that the valid user can set up MFA for their account. +If the user authenticates without MFA, the `amr` claim probably has a `pwd` (password) value. As a result, the request isn't authorized to access the page. Using the default values, the user is redirected to the **Account** > **AccessDenied** page. This behavior can be changed or you can implement your own custom logic. In this example, a link is added so the valid user can set up MFA for their account. ```cshtml @page @@ -489,34 +496,34 @@ You require MFA to login here Enable MFA ``` -Now only users that authenticate with MFA can access the page or website. If different MFA types are used or if 2FA is okay, the `amr` claim will have different values and needs to be processed correctly. Different OpenID Connect servers also return different values for this claim and might not follow the [Authentication Method Reference Values](https://tools.ietf.org/html/draft-ietf-oauth-amr-values-08) specification. +After this change, only users that authenticate with MFA can access the page or website. If different MFA types are used, or if 2FA is permitted, the `amr` claim has different values and needs to be processed correctly. Different OpenID Connect servers also return different values for this claim. These values might not follow the [IETF Authentication Method Reference Values](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-amr-values-08) specification. -When logging in without MFA (for example, using just a password): +When the user signs in without MFA (for example, by using only a password): -* The `amr` has the `pwd` value: +* The `amr` claim has the `pwd` password value: - ![amr has the pwd value](~/security/authentication/mfa/_static/require_mfa_oidc_02.png) + :::image type="content" source="~/security/authentication/mfa/_static/require_mfa_oidc_02.png" alt-text="Screenshot of source code and the Watch window where the 'amr' claim has the 'pwd' password value."::: * Access is denied: - ![Access is denied](~/security/authentication/mfa/_static/require_mfa_oidc_03.png) + :::image type="content" source="~/security/authentication/mfa/_static/require_mfa_oidc_03.png" alt-text="Screenshot showing access is denied when the user signs in without MFA."::: -Alternatively, logging in using OTP with Identity: +Alternatively, when the user signs in by using OTP with Identity, the `amr` claim has the `mfa` value: -![Logging in using OTP with Identity](~/security/authentication/mfa/_static/require_mfa_oidc_01.png) +:::image type="content" source="~/security/authentication/mfa/_static/require_mfa_oidc_01.png" alt-text="Screenshot of source code and the Watch window where the 'amr' claim has the 'mfa' value."::: -### OIDC and OAuth Parameter Customization +### OIDC and OAuth parameter customization -The OAuth and OIDC authentication handlers option allows customization of authorization message parameters that are usually included as part of the redirect query string: +The OAuth and OIDC authentication handlers option allows customization of authorization message parameters that are commonly included as part of the redirect query string: :::code language="csharp" source="~/security/authentication/mfa/samples9/WebAddOpenIdConnect/Program.cs" id="snippet_1" ::: -## Additional resources +## Related content * [Enable QR Code generation for TOTP authenticator apps in ASP.NET Core](xref:security/authentication/identity-enable-qrcodes) -* [Passwordless authentication options for Azure Active Directory](/azure/active-directory/authentication/concept-authentication-passwordless) -* [FIDO2 .NET library for FIDO2 / WebAuthn Attestation and Assertion using .NET](https://github.com/abergs/fido2-net-lib) -* [WebAuthn Awesome](https://github.com/herrjemand/awesome-webauthn) +* [Authentication methods in Microsoft Entra ID - passkeys (FIDO2)](/entra/identity/authentication/concept-authentication-passkeys-fido2) +* [FIDO2 .NET library for FIDO2 / WebAuthn attestation and assertion with .NET](https://github.com/passwordless-lib/fido2-net-lib) (GitHub) +* [WebAuthn and Passkeys Awesome](https://github.com/yackermann/awesome-webauthn) (GitHub) :::moniker-end diff --git a/aspnetcore/security/authorization/iauthorizationpolicyprovider.md b/aspnetcore/security/authorization/iauthorizationpolicyprovider.md index 81d4d1cfa4c7..e4151e1f12b4 100644 --- a/aspnetcore/security/authorization/iauthorizationpolicyprovider.md +++ b/aspnetcore/security/authorization/iauthorizationpolicyprovider.md @@ -1,48 +1,57 @@ --- -title: Custom Authorization Policy Providers in ASP.NET Core +title: Custom Authorization Policy Providers author: mjrousos description: Learn how to use a custom IAuthorizationPolicyProvider in an ASP.NET Core app to dynamically generate authorization policies. ms.author: wpickett ms.custom: mvc -ms.date: 11/14/2019 +ms.date: 05/15/2026 uid: security/authorization/iauthorizationpolicyprovider + +# customer intent: As an ASP.NET developer, I want to use a custom IAuthorizationPolicyProvider in my ASP.NET Core app, so I can dynamically generate authorization policies. --- -# Custom Authorization Policy Providers using IAuthorizationPolicyProvider in ASP.NET Core +# Use custom authorization policy providers with IAuthorizationPolicyProvider in ASP.NET Core By [Mike Rousos](https://github.com/mjrousos) -Typically when using [policy-based authorization](xref:security/authorization/policies), policies are registered by calling `AuthorizationOptions.AddPolicy` as part of authorization service configuration. In some scenarios, it may not be possible (or desirable) to register all authorization policies in this way. In those cases, you can [use a custom `IAuthorizationPolicyProvider`](#ci) to control how authorization policies are supplied. +In a typical implementation with [policy-based authorization](xref:security/authorization/policies), policies are registered by calling `AuthorizationOptions.AddPolicy` as part of authorization service configuration. Sometimes, it might not be possible (or desirable) to register all authorization policies in this manner. In these scenarios, you can [implement a custom IAuthorizationPolicyProvider](#use-a-custom-iauthorizationpolicyprovider) to control how authorization policies are provided. + +Examples of scenarios where a custom might be useful include: + +* Use an external service to provide policy evaluation. + +* Support a large range of policies (for different room numbers or ages, for example), where it doesn't make sense to add each individual authorization policy with an `AuthorizationOptions.AddPolicy` call. + +* Create policies at runtime based on information in an external data source (like a database) or determine authorization requirements dynamically through another mechanism. -Examples of scenarios where a custom may be useful include: +This article describes how to implement the `IAuthorizationPolicyProvider` interface to use a custom authorization policy provider for your ASP.NET Core app. -* Using an external service to provide policy evaluation. -* Using a large range of policies (for different room numbers or ages, for example), so it doesn't make sense to add each individual authorization policy with an `AuthorizationOptions.AddPolicy` call. -* Creating policies at runtime based on information in an external data source (like a database) or determining authorization requirements dynamically through another mechanism. +## Sample code -[View or download sample code](https://github.com/dotnet/aspnetcore/tree/v3.1.3/src/Security/samples/CustomPolicyProvider) from the [AspNetCore GitHub repository](https://github.com/dotnet/AspNetCore). Download the dotnet/AspNetCore repository ZIP file. Unzip the file. Navigate to the *src/Security/samples/CustomPolicyProvider* project folder. +[View or download the sample code](https://github.com/dotnet/aspnetcore/tree/v3.1.3/src/Security/samples/CustomPolicyProvider) from the [AspNetCore GitHub repository](https://github.com/dotnet/AspNetCore). + +Download the dotnet/AspNetCore repository ZIP file, and unzip the file. The sample code is located in the *src/Security/samples/CustomPolicyProvider* project folder. ## Customize policy retrieval -ASP.NET Core apps use an implementation of the `IAuthorizationPolicyProvider` interface to retrieve authorization policies. By default, is registered and used. `DefaultAuthorizationPolicyProvider` returns policies from the `AuthorizationOptions` provided in an `IServiceCollection.AddAuthorization` call. +ASP.NET Core apps use an implementation of the `IAuthorizationPolicyProvider` interface to retrieve authorization policies. By default, the class is registered and used. `DefaultAuthorizationPolicyProvider` returns policies from the `AuthorizationOptions` provided in a call to the `IServiceCollection.AddAuthorization` method. Customize this behavior by registering a different `IAuthorizationPolicyProvider` implementation in the app's [dependency injection](xref:fundamentals/dependency-injection) container. The `IAuthorizationPolicyProvider` interface contains three APIs: -* returns an authorization policy for a given name. -* returns the default authorization policy (the policy used for `[Authorize]` attributes without a policy specified). -* returns the fallback authorization policy (the policy used by the Authorization Middleware when no policy is specified). +* The method returns an authorization policy for a given name. +* The method returns the default authorization policy, which is the policy used for `[Authorize]` attributes without a policy specified. +* The method returns the fallback authorization policy, which is the policy used by the Authorization Middleware when no policy is specified. By implementing these APIs, you can customize how authorization policies are provided. ## Parameterized authorize attribute example -One scenario where `IAuthorizationPolicyProvider` is useful is enabling custom `[Authorize]` attributes whose requirements depend on a parameter. For example, in [policy-based authorization](xref:security/authorization/policies) documentation, an age-based (“AtLeast21”) policy was used as a sample. If different controller actions in an app should be made available to users of *different* ages, it might be useful to have many different age-based policies. Instead of registering all the different age-based policies that the application will need in `AuthorizationOptions`, you can generate the policies dynamically with a custom `IAuthorizationPolicyProvider`. To make using the policies easier, you can annotate actions with custom authorization attribute like `[MinimumAgeAuthorize(20)]`. +One scenario where `IAuthorizationPolicyProvider` is useful is enabling custom `[Authorize]` attributes whose requirements depend on a parameter. For example, in [policy-based authorization](xref:security/authorization/policies) documentation, an age-based ("AtLeast21") policy is used as a sample. If different controller actions in an app are made available to users of *different* ages, it might be useful to have many different age-based policies. Rather than registering all the different age-based policies the app might need in the `AuthorizationOptions`, you can generate the policies dynamically with a custom `IAuthorizationPolicyProvider`. To make using the policies easier, you can annotate actions with custom authorization attribute like `[MinimumAgeAuthorize(20)]`. -## Custom Authorization attributes +## Custom authorization attributes -Authorization policies are identified by their names. The custom `MinimumAgeAuthorizeAttribute` described previously needs to map arguments into a string that can be used to retrieve the corresponding authorization policy. You can do this by deriving from `AuthorizeAttribute` and making the `Age` property wrap the -`AuthorizeAttribute.Policy` property. +Authorization policies are identified by their names. A custom implementation of the `MinimumAgeAuthorizeAttribute` needs to map arguments into a string that can be used to retrieve the corresponding authorization policy. To accomplish this task, you can derive from `AuthorizeAttribute` and make the `Age` property wrap the `AuthorizeAttribute.Policy` property. ```csharp internal class MinimumAgeAuthorizeAttribute : AuthorizeAttribute @@ -72,7 +81,7 @@ internal class MinimumAgeAuthorizeAttribute : AuthorizeAttribute This attribute type has a `Policy` string based on the hard-coded prefix (`"MinimumAge"`) and an integer passed in via the constructor. -You can apply it to actions in the same way as other `Authorize` attributes except that it takes an integer as a parameter. +You can apply it to actions in the same way as other `Authorize` attributes except it takes an integer as a parameter. ```csharp [MinimumAgeAuthorize(10)] @@ -81,24 +90,23 @@ public IActionResult RequiresMinimumAge10() ## Custom IAuthorizationPolicyProvider -The custom `MinimumAgeAuthorizeAttribute` makes it easy to request authorization policies for any minimum age desired. The next problem to solve is making sure that authorization policies are available for all of those different ages. This is where an `IAuthorizationPolicyProvider` is useful. +The custom `MinimumAgeAuthorizeAttribute` implementation makes it easy to request authorization policies for any minimum age desired. The next problem to solve is making sure the authorization policies are available for all different ages. This stage in the development is where an `IAuthorizationPolicyProvider` is useful. -When using `MinimumAgeAuthorizationAttribute`, the authorization policy names will follow the pattern `"MinimumAge" + Age`, so the custom `IAuthorizationPolicyProvider` should generate authorization policies by: +When you implement `MinimumAgeAuthorizeAttribute`, the authorization policy names follow the pattern `"MinimumAge" + Age`, so the custom `IAuthorizationPolicyProvider` should generate authorization policies by completing the following tasks: -* Parsing the age from the policy name. -* Using `AuthorizationPolicyBuilder` to create a new `AuthorizationPolicy` -* In this and following examples it will be assumed that the user is authenticated via a cookie. The `AuthorizationPolicyBuilder` should either be constructed with at least one authorization scheme name or always succeed. Otherwise there is no information on how to provide a challenge to the user and an exception will be thrown. -* Adding requirements to the policy based on the age with `AuthorizationPolicyBuilder.AddRequirements`. In other scenarios, you might use `RequireClaim`, `RequireRole`, or `RequireUserName` instead. +* Parse the age from the policy name. +* Use `AuthorizationPolicyBuilder` to create a new `AuthorizationPolicy`. +* This example and later examples assume the user is authenticated by using a cookie. As such, the `AuthorizationPolicyBuilder` should either be constructed with at least one authorization scheme name or always succeed. Otherwise, there's no information on how to provide a challenge to the user and an exception is thrown. +* Add requirements to the policy based on the age with the `AuthorizationPolicyBuilder.AddRequirements` method. In other scenarios, you might instead use the `RequireClaim`, `RequireRole`, or `RequireUserName` methods. ```csharp internal class MinimumAgePolicyProvider : IAuthorizationPolicyProvider { const string POLICY_PREFIX = "MinimumAge"; - // Policies are looked up by string name, so expect 'parameters' (like age) - // to be embedded in the policy names. This is abstracted away from developers - // by the more strongly-typed attributes derived from AuthorizeAttribute - // (like [MinimumAgeAuthorize()] in this sample) + // Policy lookup is by string name. Expect 'parameters' (like age) to be embedded in policy names. + // The process is abstracted away from developers by the more strongly-typed attributes + // derived from AuthorizeAttribute (like [MinimumAgeAuthorize()] in this sample). public Task GetPolicyAsync(string policyName) { if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase) && @@ -116,22 +124,23 @@ internal class MinimumAgePolicyProvider : IAuthorizationPolicyProvider ## Multiple authorization policy providers -When using custom `IAuthorizationPolicyProvider` implementations, keep in mind that ASP.NET Core only uses one instance of `IAuthorizationPolicyProvider`. If a custom provider isn't able to provide authorization policies for all policy names that will be used, it should defer to a backup provider. +When using custom `IAuthorizationPolicyProvider` implementations, keep in mind that ASP.NET Core only uses one instance of `IAuthorizationPolicyProvider`. If a custom provider can't provide authorization policies for all policy names to be used, it should defer to a backup provider. For example, consider an application that needs both custom age policies and more traditional role-based policy retrieval. Such an app could use a custom authorization policy provider that: -* Attempts to parse policy names. +* Attempts to parse policy names. * Calls into a different policy provider (like `DefaultAuthorizationPolicyProvider`) if the policy name doesn't contain an age. -The example `IAuthorizationPolicyProvider` implementation shown above can be updated to use the `DefaultAuthorizationPolicyProvider` by creating a backup policy provider in its constructor (to be used in case the policy name doesn't match its expected pattern of 'MinimumAge' + age). +You can update the `IAuthorizationPolicyProvider` implementation described earlier to use the `DefaultAuthorizationPolicyProvider` by creating a backup policy provider in its constructor. The backup is available in case the policy name doesn't match its expected pattern of `"MinimumAge" + Age`. ```csharp private DefaultAuthorizationPolicyProvider BackupPolicyProvider { get; } public MinimumAgePolicyProvider(IOptions options) { - // ASP.NET Core only uses one authorization policy provider, so if the custom implementation - // doesn't handle all policies it should fall back to an alternate provider. + // ASP.NET Core only uses one authorization policy provider. + // If the custom implementation doesn't handle all policies, + // it should fall back to an alternate provider. BackupPolicyProvider = new DefaultAuthorizationPolicyProvider(options); } ``` @@ -147,18 +156,18 @@ return BackupPolicyProvider.GetPolicyAsync(policyName); In addition to providing named authorization policies, a custom `IAuthorizationPolicyProvider` needs to implement `GetDefaultPolicyAsync` to provide an authorization policy for `[Authorize]` attributes without a policy name specified. -In many cases, this authorization attribute only requires an authenticated user, so you can make the necessary policy with a call to `RequireAuthenticatedUser`: +In many cases, this authorization attribute only requires an authenticated user, so you can make the necessary policy with a call to the `RequireAuthenticatedUser` method: ```csharp public Task GetDefaultPolicyAsync() => Task.FromResult(new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build()); ``` -As with all aspects of a custom `IAuthorizationPolicyProvider`, you can customize this, as needed. In some cases, it may be desirable to retrieve the default policy from a fallback `IAuthorizationPolicyProvider`. +As with all aspects of a custom `IAuthorizationPolicyProvider`, you can make customizations, as needed. In some cases, it might be desirable to retrieve the default policy from a fallback `IAuthorizationPolicyProvider`. ## Fallback policy -A custom `IAuthorizationPolicyProvider` can optionally implement `GetFallbackPolicyAsync` to provide a policy that's used when [combining policies](xref:Microsoft.AspNetCore.Authorization.AuthorizationPolicy.Combine%2A) and when no policies are specified. If `GetFallbackPolicyAsync` returns a non-null policy, the returned policy is used by the Authorization Middleware when no policies are specified for the request. +A custom `IAuthorizationPolicyProvider` can optionally implement the `GetFallbackPolicyAsync` method to provide a policy to use when [combining policies](xref:Microsoft.AspNetCore.Authorization.AuthorizationPolicy.Combine%2A) and when no policies are specified. If the `GetFallbackPolicyAsync` method returns a non-null policy, the returned policy is used by the Authorization Middleware when no policies are specified for the request. If no fallback policy is required, the provider can return `null` or defer to the fallback provider: @@ -167,17 +176,19 @@ public Task GetFallbackPolicyAsync() => Task.FromResult(null); ``` - - ## Use a custom IAuthorizationPolicyProvider To use custom policies from an `IAuthorizationPolicyProvider`, you ***must***: * Register the appropriate `AuthorizationHandler` types with dependency injection (described in [policy-based authorization](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler)), as with all policy-based authorization scenarios. -* Register the custom `IAuthorizationPolicyProvider` type in the app's dependency injection service collection in `Startup.ConfigureServices` to replace the default policy provider. + +* Register the custom `IAuthorizationPolicyProvider` type in the application dependency injection service collection in `Startup.ConfigureServices` and replace the default policy provider. ```csharp services.AddSingleton(); ``` -A complete custom `IAuthorizationPolicyProvider` sample is available in the [dotnet/aspnetcore GitHub repository](https://github.com/dotnet/aspnetcore/tree/v3.1.3/src/Security/samples/CustomPolicyProvider). +## Related content + +* [Complete custom 'IAuthorizationPolicyProvider' sample (GitHub)](https://github.com/dotnet/aspnetcore/tree/v3.1.3/src/Security/samples/CustomPolicyProvider) +* diff --git a/aspnetcore/security/authorization/introduction.md b/aspnetcore/security/authorization/introduction.md index d29f0dc6bd2a..2e5d4ad4daef 100644 --- a/aspnetcore/security/authorization/introduction.md +++ b/aspnetcore/security/authorization/introduction.md @@ -3,30 +3,30 @@ title: Introduction to authorization in ASP.NET Core author: wadepickett description: Learn the basics of authorization and how authorization works in ASP.NET Core apps. ms.author: wpickett -ms.date: 10/14/2016 +ms.date: 05/15/2026 uid: security/authorization/introduction + +# customer intent: As an ASP.NET developer, I want to learn about authorization in ASP.NET Core, so I can use authorization in my apps. --- # Introduction to authorization in ASP.NET Core - - -Authorization refers to the process that determines what a user is able to do. For example, an administrative user is allowed to create a document library, add documents, edit documents, and delete them. A non-administrative user working with the library is only authorized to read the documents. +Authorization refers to the process that determines what a user is able to do. For example, an administrative user is allowed to create a document library, add documents, edit documents, and delete them. A nonadministrative user working with the library is only authorized to read the documents. -Authorization is separate and distinct from authentication. However, authorization relies on an authentication mechanism. Authentication is the process of verifying a user's identity, which may result in the creation of one or more identity objects for the user. +Authorization is separate and distinct from authentication. However, authorization relies on an authentication mechanism. Authentication is the process of verifying a user's identity, which might result in the creation of one or more identity objects for the user. For more information about authentication in ASP.NET Core, see . ## Authorization types -ASP.NET Core authorization provides a simple, declarative [role](xref:security/authorization/roles) and a rich [policy-based](xref:security/authorization/policies) model. Authorization is expressed in requirements, and handlers evaluate a user's claims against requirements. Imperative checks can be based on simple policies or policies which evaluate both the user identity and properties of the resource that the user is attempting to access. +ASP.NET Core authorization provides a simple declarative [role](xref:security/authorization/roles) and a rich [policy-based](xref:security/authorization/policies) model. Authorization is expressed in requirements, and handlers evaluate a user's claims against requirements. Imperative checks can be based on simple policies or policies that evaluate both the user identity and properties of the resource that the user is attempting to access. ## Namespaces -Authorization components, including the `AuthorizeAttribute` and `AllowAnonymousAttribute` attributes, are found in the `Microsoft.AspNetCore.Authorization` namespace. +Authorization components, including the `AuthorizeAttribute` and `AllowAnonymousAttribute` attributes, are defined in the `Microsoft.AspNetCore.Authorization` namespace. Consult the documentation on [simple authorization](xref:security/authorization/simple). -## Additional resources +## Related content * * diff --git a/aspnetcore/security/data-protection/consumer-apis/password-hashing.md b/aspnetcore/security/data-protection/consumer-apis/password-hashing.md index a4584018dbdd..6a1ae9d5c1c0 100644 --- a/aspnetcore/security/data-protection/consumer-apis/password-hashing.md +++ b/aspnetcore/security/data-protection/consumer-apis/password-hashing.md @@ -3,21 +3,29 @@ title: Hash passwords in ASP.NET Core author: wadepickett description: Learn how to hash passwords using the ASP.NET Core Data Protection APIs. ms.author: wpickett -ms.date: 10/14/2016 +ms.date: 05/15/2026 uid: security/data-protection/consumer-apis/password-hashing + +# customer intent: As an ASP.NET developer, I want to use the Data Protection APIs, so I can hash passwords in my ASP.NET Core apps. --- # Hash passwords in ASP.NET Core -This article shows how to call the [`KeyDerivation.Pbkdf2`](/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivation.pbkdf2) method which allows hashing a password using the [PBKDF2 algorithm](https://tools.ietf.org/html/rfc2898#section-5.2). +This article shows how to call the [KeyDerivation.Pbkdf2](/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivation.pbkdf2) method, which allows hashing a password with the PBKDF2 algorithm, as described in [RFC 2898, Section 5.2](https://datatracker.ietf.org/doc/html/rfc2898#section-5.2). + +The `KeyDerivation.Pbkdf2` API is a low-level cryptographic primitive. The intended use is for integrating apps into an existing protocol or cryptographic system. > [!WARNING] -> The `KeyDerivation.Pbkdf2` API is a low-level cryptographic primitive and is intended to be used to integrate apps into an existing protocol or cryptographic system. `KeyDerivation.Pbkdf2` should not be used in new apps which support password based login and need to store hashed passwords in a datastore. New apps should use [`PasswordHasher`](/dotnet/api/microsoft.aspnetcore.identity.passwordhasher-1). For more information on `PasswordHasher`, see [Exploring the ASP.NET Core Identity PasswordHasher](https://andrewlock.net/exploring-the-asp-net-core-identity-passwordhasher/). +> `KeyDerivation.Pbkdf2` shouldn't be used in new apps that support password-based sign in and which need to store hashed passwords in a datastore. New apps should use the [PasswordHasher](/dotnet/api/microsoft.aspnetcore.identity.passwordhasher-1) class. For more information, see [Exploring the ASP.NET Core Identity PasswordHasher](https://andrewlock.net/exploring-the-asp-net-core-identity-passwordhasher/). + +The data protection code base includes a NuGet package [Microsoft.AspNetCore.Cryptography.KeyDerivation](https://www.nuget.org/packages/Microsoft.AspNetCore.Cryptography.KeyDerivation/) that contains cryptographic key derivation functions. This package is a standalone component and has no dependencies on the rest of the data protection system. The package can be used independently. The source exists alongside the data protection code base as a convenience. -The data protection code base includes a NuGet package [Microsoft.AspNetCore.Cryptography.KeyDerivation](https://www.nuget.org/packages/Microsoft.AspNetCore.Cryptography.KeyDerivation/) which contains cryptographic key derivation functions. This package is a standalone component and has no dependencies on the rest of the data protection system. It can be used independently. The source exists alongside the data protection code base as a convenience. +## Generate key with 'KeyDerivation.Pbkdf2' + +The following code shows how to use the `KeyDerivation.Pbkdf2` method to generate a shared secret key. > [!WARNING] -> The following code shows how to use `KeyDerivation.Pbkdf2` to generate a shared secret key. It should not be used to hash a password for storage in a datastore. +> Don't call the `KeyDerivation.Pbkdf2` method to hash a password for storage in a datastore. @@ -33,6 +41,11 @@ The data protection code base includes a NuGet package [Microsoft.AspNetCore.Cry :::moniker-end -See the [source code](https://github.com/dotnet/AspNetCore/blob/main/src/Identity/Extensions.Core/src/PasswordHasher.cs) for ASP.NET Core Identity's `PasswordHasher` type for a real-world use case. +For a real-world use case of the ASP.NET Core Identity `PasswordHasher` type, see the [source code](https://github.com/dotnet/AspNetCore/blob/main/src/Identity/Extensions.Core/src/PasswordHasher.cs) on GitHub. [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] + +## Related content + +- [Exploring the ASP.NET Core Identity 'PasswordHasher' type](https://andrewlock.net/exploring-the-asp-net-core-identity-passwordhasher/) +- [KeyDerivation.Pbkdf2](/dotnet/api/microsoft.aspnetcore.cryptography.keyderivation.keyderivation.pbkdf2)