Service | Microsoft Docs article | Related commit history on GitHub | Change details |
---|---|---|---|
active-directory-b2c | Access Tokens | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/access-tokens.md | To request an access token, you need an authorization code. Below is an example In the following example, you replace these values in the query string: -- `<tenant-name>` - The name of your [Azure AD B2C tenant](tenant-management.md#get-your-tenant-name). If you're using a custom domain, replace `tenant-name.b2clogin.com` with your domain, such as `contoso.com`. +- `<tenant-name>` - The name of your [Azure AD B2C tenant](tenant-management-read-tenant-name.md#get-your-tenant-name). If you're using a custom domain, replace `tenant-name.b2clogin.com` with your domain, such as `contoso.com`. - `<policy-name>` - The name of your custom policy or user flow. - `<application-ID>` - The application identifier of the web application that you registered to support the user flow. - `<application-ID-URI>` - The application identifier URI that you set under **Expose an API** blade of the client application. |
active-directory-b2c | Active Directory Technical Profile | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/active-directory-technical-profile.md | |
active-directory-b2c | Client Credentials Grant Flow | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/client-credentials-grant-flow.md | There are no specific actions to enable the client credentials for user flows or `https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/<policy>/oauth2/v2.0/token` -- Replace `<tenant-name>` with the [name](tenant-management.md#get-your-tenant-name) of your Azure AD B2C tenant. For example, `contoso.b2clogin.com`.+- Replace `<tenant-name>` with the [name]( tenant-management-read-tenant-name.md#get-your-tenant-name) of your Azure AD B2C tenant. For example, `contoso.b2clogin.com`. - Replace `<policy>` with the full name of your user flow, or custom policy. Note, all types of user flows and custom policies support client credentials flow. You can use any user flow or custom policy you have, or create a new one, such as sign-up or sign-in. | Key | Value | |
active-directory-b2c | Configure A Sample Node Web App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-a-sample-node-web-app.md | Open your web app in a code editor such as Visual Studio Code. Under the project ||| |`APP_CLIENT_ID`|The **Application (client) ID** for the web app you registered in [step 2.1](#step-2-register-a-web-application). | |`APP_CLIENT_SECRET`|The client secret value for the web app you created in [step 2.2](#step-22-create-a-web-app-client-secret) |-|`SIGN_UP_SIGN_IN_POLICY_AUTHORITY`|The **Sign in and sign up** user flow authority such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>`. Replace `<your-tenant-name>` with the name of your tenant and `<sign-in-sign-up-user-flow-name>` with the name of your Sign in and Sign up user flow such as `B2C_1_susi`. Learn how to [Get your tenant name](tenant-management.md#get-your-tenant-name). | +|`SIGN_UP_SIGN_IN_POLICY_AUTHORITY`|The **Sign in and sign up** user flow authority such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>`. Replace `<your-tenant-name>` with the name of your tenant and `<sign-in-sign-up-user-flow-name>` with the name of your Sign in and Sign up user flow such as `B2C_1_susi`. Learn how to [Get your tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). | |`RESET_PASSWORD_POLICY_AUTHORITY`| The **Reset password** user flow authority such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<reset-password-user-flow-name>`. Replace `<your-tenant-name>` with the name of your tenant and `<reset-password-user-flow-name>` with the name of your Reset password user flow such as `B2C_1_reset_password_node_app`.| |`EDIT_PROFILE_POLICY_AUTHORITY`|The **Profile editing** user flow authority such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<profile-edit-user-flow-name>`. Replace `<your-tenant-name>` with the name of your tenant and `<reset-password-user-flow-name>` with the name of your reset password user flow such as `B2C_1_edit_profile_node_app`. | |`AUTHORITY_DOMAIN`| The Azure AD B2C authority domain such as `https://<your-tenant-name>.b2clogin.com`. Replace `<your-tenant-name>` with the name of your tenant.| |
active-directory-b2c | Configure Authentication In Azure Static App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-in-azure-static-app.md | Once you've added the app ID and secrete, use the following steps to add the Azu } ``` -1. Replace `<TENANT_NAME>` with the first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com/contoso.onmicrosoft.com`). +1. Replace `<TENANT_NAME>` with the first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com/contoso.onmicrosoft.com`). 1. Replace `<POLICY_NAME>` with the user flows or custom policy you created in [step 1](#step-1-configure-your-user-flow). ## Step 4: Check the Azure Static Web APP |
active-directory-b2c | Configure Authentication In Azure Web App File Based | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-in-azure-web-app-file-based.md | Once you've the added the app ID and secret, use the following steps to add the } ``` -1. Replace `<TENANT_NAME>` with the first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com/contoso.onmicrosoft.com`). +1. Replace `<TENANT_NAME>` with the first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com/contoso.onmicrosoft.com`). 1. Replace `<POLICY_NAME>` with the user flows or custom policy you created in [step 1](#step-1-configure-your-user-flow). ## Step 4: Check the Azure Web app |
active-directory-b2c | Configure Authentication In Azure Web App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-in-azure-web-app.md | To register your application, follow these steps: https://<TENANT_NAME>.b2clogin.com/<TENANT_NAME>.onmicrosoft.com/<POLICY_NAME>/v2.0/.well-known/openid-configuration ``` - 1. Replace `<TENANT_NAME>` with the first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com/contoso.onmicrosoft.com`). If you have a [custom domains](custom-domain.md) configure, you can use that custom domain. Replace your B2C tenant name, contoso.onmicrosoft.com, in the authentication request URL with your tenant ID GUID. For example, you can change `https://fabrikamb2c.b2clogin.com/contoso.onmicrosoft.com/` to `https://account.contosobank.co.uk/<tenant ID GUID>/`. + 1. Replace `<TENANT_NAME>` with the first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com/contoso.onmicrosoft.com`). If you have a [custom domains](custom-domain.md) configure, you can use that custom domain. Replace your B2C tenant name, contoso.onmicrosoft.com, in the authentication request URL with your tenant ID GUID. For example, you can change `https://fabrikamb2c.b2clogin.com/contoso.onmicrosoft.com/` to `https://account.contosobank.co.uk/<tenant ID GUID>/`. 1. Replace the `<POLICY_NAME>` with the user flows or custom policy you created in [step 1](#step-1-configure-your-user-flow). |
active-directory-b2c | Configure Authentication In Sample Node Web App With Api | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-in-sample-node-web-app-with-api.md | Open your web app in a code editor such as Visual Studio Code. Under the `call-p ||| |`APP_CLIENT_ID`|The **Application (client) ID** for the web app you registered in [step 2.3](#step-23-register-the-web-app). | |`APP_CLIENT_SECRET`|The client secret value for the web app you created in [step 2.4](#step-24-create-a-client-secret) |-|`SIGN_UP_SIGN_IN_POLICY_AUTHORITY`|The **Sign in and sign up** user flow authority for the user flow you created in [step 1](#step-1-configure-your-user-flow) such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>`. Replace `<your-tenant-name>` with the name of your tenant and `<sign-in-sign-up-user-flow-name>` with the name of your Sign in and Sign up user flow such as `B2C_1_susi`. Learn how to [Get your tenant name](tenant-management.md#get-your-tenant-name). | +|`SIGN_UP_SIGN_IN_POLICY_AUTHORITY`|The **Sign in and sign up** user flow authority for the user flow you created in [step 1](#step-1-configure-your-user-flow) such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>`. Replace `<your-tenant-name>` with the name of your tenant and `<sign-in-sign-up-user-flow-name>` with the name of your Sign in and Sign up user flow such as `B2C_1_susi`. Learn how to [Get your tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). | |`AUTHORITY_DOMAIN`| The Azure AD B2C authority domain such as `https://<your-tenant-name>.b2clogin.com`. Replace `<your-tenant-name>` with the name of your tenant.| |`APP_REDIRECT_URI`| The application redirect URI where Azure AD B2C will return authentication responses (tokens). It matches the **Redirect URI** you set while registering your app in Azure portal. This URL need to be publicly accessible. Leave the value as is.| |`LOGOUT_ENDPOINT`| The Azure AD B2C sign out endpoint such as `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000`. Replace `<your-tenant-name>` with the name of your tenant and `<sign-in-sign-up-user-flow-name>` with the name of your Sign in and Sign up user flow such as `B2C_1_susi`.| To get the web API sample code, do one of the following: 1. Modify the variable values with the user flow and application registration you created earlier: - - For `tenantName`, use the [name of your tenant name](tenant-management.md#get-your-tenant-name) such as `fabrikamb2c`. + - For `tenantName`, use the [name of your tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) such as `fabrikamb2c`. - For `clientID`, use the **Application (Client) ID** for the web API you created in [step 2.1](#step-21-register-the-web-api-application). |
active-directory-b2c | Configure Authentication Sample Android App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-android-app.md | Update the following app settings properties: ||| | [client_id](../active-directory/develop/msal-client-application-configuration.md#client-id) | The mobile application ID from [step 2.3](#step-23-register-the-mobile-app). | | [redirect_uri](../active-directory/develop/msal-client-application-configuration.md#redirect-uri) | The mobile application redirect URI from [step 2.3](#step-23-register-the-mobile-app). | -| [authorities](../active-directory/develop/msal-client-application-configuration.md#authority)| The authority is a URL that indicates a directory that the MSAL can request tokens from. Use the following format: `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<your-sign-in-sign-up-policy>`. Replace `<your-tenant-name>` with your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). Then, replace `<your-sign-in-sign-up-policy>` with the user flows or custom policy that you created in [step 1](#step-1-configure-your-user-flow). | +| [authorities](../active-directory/develop/msal-client-application-configuration.md#authority)| The authority is a URL that indicates a directory that the MSAL can request tokens from. Use the following format: `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<your-sign-in-sign-up-policy>`. Replace `<your-tenant-name>` with your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). Then, replace `<your-sign-in-sign-up-policy>` with the user flows or custom policy that you created in [step 1](#step-1-configure-your-user-flow). | | | | Open the `B2CConfiguration` class, and update the following class members: |Key |Value | ||| | Policies| The list of user flows or custom policies that you created in [step 1](#step-1-configure-your-user-flow).|-| azureAdB2CHostName| The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| -| tenantName| Your Azure AD B2C tenant full [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| +| azureAdB2CHostName| The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| +| tenantName| Your Azure AD B2C tenant full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| | scopes| The web API scopes that you created in [step 2.4](#step-24-grant-the-mobile-app-permissions-for-the-web-api).| | | | |
active-directory-b2c | Configure Authentication Sample Angular Spa App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-angular-spa-app.md | Now that you've obtained the SPA sample, update the code with your Azure AD B2C |Section |Key |Value | |||| | b2cPolicies | names |The user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). |-| b2cPolicies | authorities | Replace `your-tenant-name` with your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). For example, use `contoso.onmicrosoft.com`. Then, replace the policy name with the user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). For example: `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<your-sign-in-sign-up-policy>`. | -| b2cPolicies | authorityDomain|Your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). For example: `contoso.onmicrosoft.com`. | +| b2cPolicies | authorities | Replace `your-tenant-name` with your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example, use `contoso.onmicrosoft.com`. Then, replace the policy name with the user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). For example: `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<your-sign-in-sign-up-policy>`. | +| b2cPolicies | authorityDomain|Your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example: `contoso.onmicrosoft.com`. | | Configuration | clientId | The Angular application ID from [step 2.3](#23-register-the-angular-app). | | protectedResources| endpoint| The URL of the web API: `http://localhost:5000/api/todolist`. | | protectedResources| scopes| The web API scopes that you created in [step 2.2](#22-configure-scopes). For example: `b2cScopes: ["https://<your-tenant-name>.onmicrosoft.com/tasks-api/tasks.read"]`. | In the sample folder, open the *config.json* file. This file contains informatio |Section |Key |Value | ||||-|credentials|tenantName| The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). For example: `contoso`.| +|credentials|tenantName| The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example: `contoso`.| |credentials|clientID| The web API application ID from step [2.1](#21-register-the-web-api-application). In the [earlier diagram](#app-registration), it's the application with **App ID: 2**.|-|credentials| issuer| (Optional) The token issuer `iss` claim value. Azure AD B2C by default returns the token in the following format: `https://<your-tenant-name>.b2clogin.com/<your-tenant-ID>/v2.0/`. Replace `<your-tenant-name>` with the first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). Replace `<your-tenant-ID>` with your [Azure AD B2C tenant ID](tenant-management.md#get-your-tenant-id). | +|credentials| issuer| (Optional) The token issuer `iss` claim value. Azure AD B2C by default returns the token in the following format: `https://<your-tenant-name>.b2clogin.com/<your-tenant-ID>/v2.0/`. Replace `<your-tenant-name>` with the first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). Replace `<your-tenant-ID>` with your [Azure AD B2C tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). | |policies|policyName|The user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). If your application uses multiple user flows or custom policies, specify only one. For example, use the sign-up or sign-in user flow.| | resource| scope | The scopes of your web API application registration from [step 2.5](#25-grant-permissions). | |
active-directory-b2c | Configure Authentication Sample Ios App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-ios-app.md | Update the following class members: |Key |Value | |||-|kTenantName| Your Azure AD B2C tenant full [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| -|kAuthorityHostName|The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.b2clogin.com`).| +|kTenantName| Your Azure AD B2C tenant full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| +|kAuthorityHostName|The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.b2clogin.com`).| |kClientID|The mobile application ID from [step 2.3](#step-23-register-the-mobile-app).| |kRedirectUri|The mobile application redirect URI from [step 2.3](#step-23-register-the-mobile-app), `msauth.com.microsoft.identitysample.MSALiOS://auth`.| |kSignupOrSigninPolicy| The sign-up or sign-in user flow or custom policy you created in [step 1](#step-1-configure-your-user-flow).| |
active-directory-b2c | Configure Authentication Sample Python Web App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-python-web-app.md | Open the *app_config.py* file. This file contains information about your Azure A |Key |Value | |||-|`b2c_tenant`| The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso`).| +|`b2c_tenant`| The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso`).| |`CLIENT_ID`| The web API application ID from [step 2.1](#step-21-register-the-app).| |`CLIENT_SECRET`| The client secret value you created in [step 2.2](#step-22-create-a-web-app-client-secret). To help increase security, consider storing it instead in an environment variable, as recommended in the comments. | |`*_user_flow`|The user flows or custom policy you created in [step 1](#step-1-configure-your-user-flow).| |
active-directory-b2c | Configure Authentication Sample React Spa App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-react-spa-app.md | Now that you've obtained the SPA sample, update the code with your Azure AD B2C |Section |Key |Value | |||| | b2cPolicies | names |The user flows or custom policies that you created in [step 1](#step-1-configure-your-user-flow). |-| b2cPolicies | authorities | Replace `your-tenant-name` with your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). For example, use `contoso.onmicrosoft.com`. Then, replace the policy name with the user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). For example: `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<your-sign-in-sign-up-policy>`. | -| b2cPolicies | authorityDomain|Your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). For example: `contoso.onmicrosoft.com`. | +| b2cPolicies | authorities | Replace `your-tenant-name` with your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example, use `contoso.onmicrosoft.com`. Then, replace the policy name with the user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). For example: `https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<your-sign-in-sign-up-policy>`. | +| b2cPolicies | authorityDomain|Your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example: `contoso.onmicrosoft.com`. | | Configuration | clientId | The React application ID from [step 2.3](#23-register-the-react-app). | | protectedResources| endpoint| The URL of the web API: `http://localhost:5000/hello`. | | protectedResources| scopes| The web API scopes that you created in [step 2.2](#22-configure-scopes). For example: `b2cScopes: ["https://<your-tenant-name>.onmicrosoft.com/tasks-api/tasks.read"]`. | In the sample folder, open the *authConfig.js* file. This file contains informat |Section |Key |Value | ||||-|credentials|tenantName| Your Azure AD B2C [domain/tenant name](tenant-management.md#get-your-tenant-name). For example: `contoso.ommicrosoft.com`.| +|credentials|tenantName| Your Azure AD B2C [domain/tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example: `contoso.ommicrosoft.com`.| |credentials|clientID| The web API application ID from step [2.1](#21-register-the-web-api-application). In the [earlier diagram](#app-registration), it's the application with **App ID: 2**.| |policies|policyName|The user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow). If your application uses multiple user flows or custom policies, specify only one. For example, use the sign-up or sign-in user flow.| | protectedRoutes| scopes | The scopes of your web API application registration from [step 2.5](#25-grant-permissions). | |
active-directory-b2c | Configure Authentication Sample Web App With Api | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-web-app-with-api.md | Under the project root folder, open the *appsettings.json* file. This file conta | Section | Key | Value | | | | |-|AzureAdB2C|Instance| The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). For example, `https://contoso.b2clogin.com`.| -|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name](tenant-management.md#get-your-tenant-name). For example, `contoso.onmicrosoft.com`.| +|AzureAdB2C|Instance| The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example, `https://contoso.b2clogin.com`.| +|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For example, `contoso.onmicrosoft.com`.| |AzureAdB2C|ClientId| The web API application ID from [step 2.1](#step-21-register-the-web-api-app).| |AzureAdB2C|SignUpSignInPolicyId|The user flows, or custom policy you created in [step 1](#step-1-configure-your-user-flow).| | | | | Under the project root folder, open the `appsettings.json` file. This file conta | Section | Key | Value | | | | |-| AzureAdB2C | Instance | The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| -|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| +| AzureAdB2C | Instance | The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| +|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| |AzureAdB2C|ClientId| The web application ID from [step 2.3](#step-23-register-the-web-app).| |AzureAdB2C | ClientSecret | The web application secret from [step 2.4](#step-24-create-a-web-app-client-secret). | |AzureAdB2C|SignUpSignInPolicyId|The user flows or custom policy you created in [step 1](#step-1-configure-your-user-flow).| |
active-directory-b2c | Configure Authentication Sample Web App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-web-app.md | Under the project root folder, open the *appsettings.json* file. This file conta |Section |Key |Value | ||||-|AzureAdB2C|Instance| The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| -|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| +|AzureAdB2C|Instance| The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| +|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| |AzureAdB2C|ClientId| The Web App Application (client) ID from [step 2](#step-2-register-a-web-application).| |AzureAdB2C|SignUpSignInPolicyId|The user flows or custom policy you created in [step 1](#step-1-configure-your-user-flow).| |
active-directory-b2c | Configure Authentication Sample Wpf Desktop App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/configure-authentication-sample-wpf-desktop-app.md | To create the desktop app registration, do the following: 1. Select **App registrations**, and then select **New registration**. 1. Under **Name**, enter a name for the application (for example, *desktop-app1*). 1. Under **Supported account types**, select **Accounts in any identity provider or organizational directory (for authenticating users with user flows)**. -1. Under **Redirect URI**, select **Public client/native (desktop & desktop)** and then, in the URL box, enter `https://your-tenant-name.b2clogin.com/oauth2/nativeclient`. Replace `your-tenant-name` with your [tenant name](tenant-management.md#get-your-tenant-name). For more options, see [Configure redirect URI](enable-authentication-wpf-desktop-app-options.md#configure-the-redirect-uri). +1. Under **Redirect URI**, select **Public client/native (desktop & desktop)** and then, in the URL box, enter `https://your-tenant-name.b2clogin.com/oauth2/nativeclient`. Replace `your-tenant-name` with your [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). For more options, see [Configure redirect URI](enable-authentication-wpf-desktop-app-options.md#configure-the-redirect-uri). 1. Select **Register**. 1. After the app registration is completed, select **Overview**. 1. Record the **Application (client) ID** for later use, when you configure the desktop application. Update the following class members: |Key |Value | |||-|`TenantName`|The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.b2clogin.com`).| +|`TenantName`|The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.b2clogin.com`).| |`ClientId`|The desktop application ID from [step 2.3](#step-23-register-the-desktop-app).| |`PolicySignUpSignIn`| The sign-up or sign-in user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow).| |`PolicyEditProfile`|The edit profile user flow or custom policy that you created in [step 1](#step-1-configure-your-user-flow).| |
active-directory-b2c | Custom Domain | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-domain.md | Follow these steps to create an Azure Front Door: |Tier| Select either Standard or Premium tier. Standard tier is content delivery optimized. Premium tier builds on Standard tier and is focused on security. See [Tier Comparison](../frontdoor/standard-premium/tier-comparison.md).| |Endpoint name| Enter a globally unique name for your endpoint, such as `b2cazurefrontdoor`. The **Endpoint hostname** is generated automatically. | |Origin type| Select `Custom`.|- |Origin host name| Enter `<tenant-name>.b2clogin.com`. Replace `<tenant-name>` with the [name of your Azure AD B2C tenant](tenant-management.md#get-your-tenant-name) such as `contoso.b2clogin.com`.| + |Origin host name| Enter `<tenant-name>.b2clogin.com`. Replace `<tenant-name>` with the [name of your Azure AD B2C tenant]( tenant-management-read-tenant-name.md#get-your-tenant-name) such as `contoso.b2clogin.com`.| Leave the **Caching** and **WAF policy** empty. |
active-directory-b2c | Custom Policies Series Branch User Journey | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-branch-user-journey.md | + + Title: Create branching in user journey by using Azure AD B2C custom policy ++description: Learn how to enable or disable Technical Profiles based on claims values. Learn how to branch in user journeys by enabling and disabling Azure AD B2C custom policy technical profiles. ++++++++ Last updated : 01/30/2023++++++# Create branching in user journey by using Azure Active Directory B2C custom policy ++Different users of the same app can follow different user journeys depending on the values of the data in a custom policy. Azure Active Directory B2C (Azure AD B2C) custom policies allows you to conditionally enable or disable a technical profile to achieve this capability. For example, in [Validate user inputs by using Azure AD B2C custom policy](custom-policies-series-validate-user-input.md), we used a `Precondition` to determine whether or not we should run a validation technical profile based on the value of *accountType* claim. ++A technical profile also provides a `EnabledForUserJourneys` element to allow you to specify whether or not a technical profile should run. The `EnabledForUserJourneys` element contains one of five values including *OnClaimsExistence*, which you use to specify that a technical profile should run only when a certain claim specified in the technical profile exists. Learn more about technical profile's [EnabledForUserJourneys](technicalprofiles.md#enabled-for-user-journeys) element. ++## Scenario overview ++In [Validate user inputs by using Azure AD B2C custom policy](custom-policies-series-validate-user-input.md) article, a user inputs their details in a single screen. In this article, a user needs to first select their account type, *Contoso Employee Account* or *Personal Account*. A user who selects *Contoso Employee Account* can proceed to provide further details. However, a user who selects *Personal Account* need to provide a valid invitation access code before they can proceed to provide further details. Hence, users who use *Personal Account* account type see an extra user interface to complete their journey. +++In this article, you'll learn how to use `EnabledForUserJourneys` element inside a technical profile to create different user experiences based on a claim value. First, the user selects their account type, which determines ++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Validate user inputs by using Azure AD B2C custom policy](custom-policies-series-validate-user-input.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++## Step 1 - Declare claims ++A user who selects *Personal Account* needs to provide a valid access code. So, we need a claim to hold this value: ++1. In VS Code, open the `ContosoCustomPolicy.XML` file. ++1. In the `ClaimsSchema` section, declare accessCode and isValidAccessCode claims by using the following code: ++ ```xml + <ClaimType Id="accessCode"> + <DisplayName>Access Code</DisplayName> + <DataType>string</DataType> + <UserHelpText>Enter your invitation access code.</UserHelpText> + <UserInputType>Password</UserInputType> + <Restriction> + <Pattern RegularExpression="[0-9][0-9][0-9][0-9][0-9]" HelpText="Please enter your invitation access code. It's a 5-digit number, something like 95765"/> + </Restriction> + </ClaimType> + <ClaimType Id="isValidAccessCode"> + <DataType>boolean</DataType> + </ClaimType> + ``` +++## Step 2 - Define claims transformations ++Locate the `ClaimsTransformations` element, and add the following claims transformations: ++```xml + <!<ClaimsTransformations>--> + <ClaimsTransformation Id="CheckIfIsValidAccessCode" TransformationMethod="CompareClaimToValue"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="accessCode" TransformationClaimType="inputClaim1"/> + </InputClaims> + <InputParameters> + <InputParameter Id="compareTo" DataType="string" Value="88888"/> + <InputParameter Id="operator" DataType="string" Value="equal"/> + <InputParameter Id="ignoreCase" DataType="string" Value="true"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="isValidAccessCode" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> + <ClaimsTransformation Id="ThrowIfIsNotValidAccessCode" TransformationMethod="AssertBooleanClaimIsEqualToValue"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="isValidAccessCode" TransformationClaimType="inputClaim"/> + </InputClaims> + <InputParameters> + <InputParameter Id="valueToCompareTo" DataType="boolean" Value="true"/> + </InputParameters> + </ClaimsTransformation> + <!</ClaimsTransformations>--> +``` ++We've defined two claims transformations, *CheckIfIsValidAccessCode* and *ThrowIfIsNotValidAccessCode*. *CheckIfIsValidAccessCode* uses [CompareClaimToValue](string-transformations.md#compareclaimtovalue) transformation method to compare the access code input by the user against a static value 88888 (let's use this value for testing) and assigns `true` or `false` to *isValidAccessCode* claim. *ThrowIfIsNotValidAccessCode* checks whether or not two boolean values of two claims are equal, and throws an exception if they aren't. ++## Step 3 - Configure or update technical profiles ++You now need two new self-asserted technical profiles, one to collect the account type, and the other to collect access code from the user. You also need a new claims transformation type technical profile to validate the user's access code by executing the claims transformations that you defined in [step 2](#step-2define-claims-transformations). Now that we're collecting the account type in a different self-asserted technical profile, we need to update the `UserInformationCollector` self-asserted technical profile to prevent it from collecting the account type. ++1. Locate the `ClaimsProviders` element, and then add a new claims provider using the following code: ++ ```xml + <!--<ClaimsProviders>--> + <ClaimsProvider> + <DisplayName>Technical Profiles to collect user's access code</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="AccessCodeInputCollector"> + <DisplayName>Collect Access Code Input from user Technical Profile</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <Metadata> + <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item> + <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">The access code is invalid.</Item> + <Item Key="ClaimTypeOnWhichToEnable">accountType</Item> + <Item Key="ClaimValueOnWhichToEnable">personal</Item> + </Metadata> + <DisplayClaims> + <DisplayClaim ClaimTypeReferenceId="accessCode" Required="true"/> + </DisplayClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="accessCode"/> + </OutputClaims> + <ValidationTechnicalProfiles> + <ValidationTechnicalProfile ReferenceId="CheckAccessCodeViaClaimsTransformationChecker"/> + </ValidationTechnicalProfiles> + <EnabledForUserJourneys>OnClaimsExistence</EnabledForUserJourneys> + </TechnicalProfile> + <TechnicalProfile Id="CheckAccessCodeViaClaimsTransformationChecker"> + <DisplayName>A Claims Transformations to check user's access code validity</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="isValidAccessCode"/> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="CheckIfIsValidAccessCode"/> + <OutputClaimsTransformation ReferenceId="ThrowIfIsNotValidAccessCode"/> + </OutputClaimsTransformations> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + <!--</ClaimsProviders>--> + ``` ++ We've configured two technical profiles, *AccessCodeInputCollector* and *CheckAccessCodeViaClaimsTransformationChecker*. We call the *CheckAccessCodeViaClaimsTransformationChecker* technical profile as a validation technical profile from within the *AccessCodeInputCollector* technical profile. The *CheckAccessCodeViaClaimsTransformationChecker* itself is of type Claims Transformation technical Profile, which executes the Claims Transformations we defined in [step 2](#step-2define-claims-transformations). ++ *AccessCodeInputCollector* is a Self-Asserted Technical Profile used to collect an access code from the user. It includes `EnabledForUserJourneys` element that's set to *OnClaimsExistence*. Its `Metadata` element includes a claim (*accountType*) and its value (*personal*) that activates this technical profile. ++1. Locate the `ClaimsProviders` element, and then add a new claims provider using the following code: ++ ```xml + <!--<ClaimsProviders>--> + <ClaimsProvider> + <DisplayName>Technical Profile to collect user's accountType</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="AccountTypeInputCollector"> + <DisplayName>Collect User Input Technical Profile</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <Metadata> + <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item> + </Metadata> + <DisplayClaims> + <DisplayClaim ClaimTypeReferenceId="accountType" Required="true"/> + </DisplayClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="accountType"/> + </OutputClaims> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + <!--</ClaimsProviders>--> + ``` + + We've configured a self-asserted technical profile, `AccountTypeInputCollector`, which collect the user's account type. It's the account types's value that determines whether the `AccessCodeInputCollector` self-asserted technical profile should be activated. ++1. To prevent the `UserInformationCollector` self-asserted technical profile from collecting the account type, locate the `UserInformationCollector` self-asserted technical profile, and then: + + 1. Remove the `accountType` display claim, `<DisplayClaim ClaimTypeReferenceId="accountType" Required="true"/>` from the `DisplayClaims` collection. + + 1. Remove the `accountType` output claim, `<OutputClaim ClaimTypeReferenceId="accountType"/>`, from the `OutputClaims` collection. +++## Step 4 - Update the User journey orchestration steps ++Now that you've set up your technical profiles, you need to update your user journey orchestration steps: ++1. Locate your `HelloWorldJourney` user journey and add replace all the orchestration steps with the following code: ++ ```xml + <!--<OrchestrationSteps>--> + <OrchestrationStep Order="1" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="AccountTypeInputCollectorClaimsExchange" TechnicalProfileReferenceId="AccountTypeInputCollector"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="2" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetAccessCodeClaimsExchange" TechnicalProfileReferenceId="AccessCodeInputCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="3" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="4" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="ClaimGenerator"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/> + <!--</OrchestrationSteps>--> + ``` + The orchestration steps shows that we call the technical profile in the order shown by the orchestration steps' `Order` attribute. However, the `AccessCodeInputCollector` technical profile is activated if the user selects *Personal Account* account type. ++## Step 5 - Upload custom policy file ++Follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file) to upload your policy file. If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. ++## Step 6 - Test the custom policy ++Follow the steps in [Test the custom policy](custom-policies-series-validate-user-input.md#step-6test-the-custom-policy) to test your custom policy: ++1. In the first screen, for **Account Type**, select **Personal Account**. +1. For **Access Code**, enter *88888*, and then select **Continue**. +1. Enter the rest of the details as required, and then select **Continue**. After the policy finishes execution, you're redirected to `https://jwt.ms`, and you see a decoded JWT token. +1. Repeat step 5, but this time, select **Account Type**, select **Contoso Employee Account**, and then follow the prompts. + ++## Next steps ++In [step 3](#step-3configure-or-update-technical-profiles), we enabled or disabled the technical profile by using the `EnabledForUserJourneys` element. Alternatively, you can use [Preconditions](userjourneys.md#preconditions) inside the user journey orchestration steps to execute or skip an orchestration step as we'll learn later in this series. ++Next, learn: ++- About [User Journey Orchestration Steps Preconditions](userjourneys.md#preconditions). ++- How to [Use the TrustFrameworkPolicy schema file to validate Azure AD B2C policy files](custom-policies-series-install-xml-extensions.md). |
active-directory-b2c | Custom Policies Series Call Rest Api | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-call-rest-api.md | + + Title: Call a REST API by using Azure Active Directory B2C custom policy ++description: Learn how to make an HTTP call to external API by using Azure Active Directory B2C custom policy. ++++++++ Last updated : 01/30/2023++++++# Call a REST API by using Azure Active Directory B2C custom policy ++Azure Active Directory B2C (Azure AD B2C) custom policy allows you to interact with application logic that's implemented outside of Azure AD B2C. To do so, you make an HTTP call to an endpoint. Azure AD B2C custom policies provide RESTful technical profile for this purpose. By using this capability, you can implement features that aren't available within Azure AD B2C custom policy. ++In this article, you'll learn how to: ++- Create and deploy a sample Node.js app for use as a RESTful service. ++- Make an HTTP call to the Node.js RESTful service by using the RESTful technical profile. ++- Handle or report an error that a RESTful service returns to your custom policy. +++## Scenario overview ++In [Create branching in user journey by using Azure AD B2C custom policies](custom-policies-series-branch-user-journey.md), users who select *Personal Account* need to provide a valid invitation access code to proceed. We use a static access code, but real world apps don't work this way. If the service that issues the access codes is external to your custom policy, you must make a call to that service, and pass the access code input by the user for validation. If the access code is valid, the service returns an HTTP 200 (OK) response, and Azure AD B2C issues JWT token. Otherwise, the service returns an HTTP 409 (Conflict) response, and the use must re-enter an access code. +++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Node.js](https://nodejs.org) installed in your computer. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Validate user inputs by using Azure AD B2C custom policy](custom-policies-series-validate-user-input.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++## Step 1 - Create and deploy a Node.js app ++You need to deploy an app, which will serve as your external app. Your custom policy then makes an HTTP call to this app. ++### Step 1.1 - Create the Node.js app ++1. Create a folder to host your node application, such as `access-code-app`. ++1. In your terminal, change directory into your Node app folder, such as `cd access-code-app`, and run `npm init -y`. This command creates a default `package.json` file for your Node.js project. ++1. In your terminal, run `npm install express body-parser`. This command installs the Express framework and the [body-parser](https://www.npmjs.com/package/body-parser) package. ++1. In your project, create `index.js` file. ++1. In VS Code, open the `index.js` file, and then add the following code: ++ ```JavaScript + const express = require('express'); + let bodyParser = require('body-parser') + //Create an express instance + const app = express(); + + app.use( bodyParser.json() ); // to support JSON-encoded bodies + app.use(bodyParser.urlencoded({ // to support URL-encoded bodies + extended: true + })); + + + app.post('/validate-accesscode', (req, res) => { + let accessCode = '88888'; + if(accessCode == req.body.accessCode){ + res.status(200).send(); + }else{ + let errorResponse = { + "version" :"1.0", + "status" : 409, + "code" : "errorCode", + "requestId": "requestId", + "userMessage" : "The access code you entered is incorrect. Please try again.", + "developerMessage" : `The The provided code ${req.body.accessCode} does not match the expected code for user.`, + "moreInfo" :"https://docs.microsoft.com/en-us/azure/active-directory-b2c/string-transformations" + }; + res.status(409).send(errorResponse); + } + }); + + app.listen(80, () => { + console.log(`Access code service listening on port !` + 80); + }); + ``` + + You can observe that when a user submits a wrong access code, you can return an error directly from the REST API. Custom policies allow you to return an HTTP 4xx error message, such as, 400 (bad request), or 409 (Conflict) response status code with a response JSON body formatted as shown in `errorResponse` variable. The source of the accessCode in the app could be read from a database. Learn more about [Returning validation error message](restful-technical-profile.md#returning-validation-error-message). ++1. To test the app works as expected, use the following steps: + 1. In your terminal, run the `node index.js` command to start your app server. + 1. To make a POST request similar to the one shown below, you can use an HTTP client such as [Microsoft PowerShell](https://learn.microsoft.com/powershell/scripting/overview) or [Postman](https://www.postman.com/): + + ```http + POST http://localhost/validate-accesscode HTTP/1.1 + Host: localhost + Content-Type: application/x-www-form-urlencoded + + accessCode=user-code-code + ``` + + Replace `user-code-code` with an access code input by the user, such as `54321`. If you're using PowerShell, run the following script. ++ ```powershell + $accessCode="54321" + $endpoint="http://localhost/validate-accesscode" + $body=$accessCode + $response=Invoke-RestMethod -Method Post -Uri $endpoint -Body $body + echo $response + ``` ++ If you use an incorrect access code, the response looks similar to the following JSON snippet: + + ```json + { + "version": "1.0", + "status": 409, + "code": "errorCode", + "requestId": "requestId", + "userMessage": "The access code you entered is incorrect. Please try again.", + "developerMessage": "The The provided code 54321 does not match the expected code for user.", + "moreInfo": "https://docs.microsoft.com/en-us/azure/active-directory-b2c/string-transformations" + } + ``` ++At this point, you're ready to deploy your Node.js app. ++### Step 1.2 - Deploy the Node.js app in Azure App Service ++For your custom policy to reach your Node.js app, it needs to be reachable, so, you need deploy it. In this article, you'll deploy the app by using [Azure App Service](../app-service/overview-vnet-integration.md), but you use an alternative hosting approach. ++Follow the steps in [Deploy your app to Azure](../app-service/quickstart-nodejs.md#deploy-to-azure) to deploy your Node.js app to Azure. For the **Name** of the app, use a descriptive name such as `custompolicyapi`. Hence: ++- App URL looks similar to `https://custompolicyapi.azurewebsites.net`. ++- Service endpoint looks similar to `https://custompolicyapi.azurewebsites.net/validate-accesscode`. ++You can test the app you've deployed by using an HTTP client such as [Microsoft PowerShell](https://learn.microsoft.com/powershell/scripting/overview) or [Postman](https://www.postman.com/). This time, use `https://custompolicyapi.azurewebsites.net/validate-accesscode` URL as the endpoint. ++## Step 2 - Call the REST API ++Now that your app is running, you need to make an HTTP call from your custom policy. Azure AD B2C custom policy provides a [RESTful technical profile](restful-technical-profile.md#returning-validation-error-message) that you use to call an external service. +++### Step 2.1 - Define a RESTful technical profile ++In your `ContosoCustomPolicy.XML` file, locate the `ClaimsProviders` section, and define a new RESTful technical profile by using the following code: ++```xml + <!--<ClaimsProviders>--> + <ClaimsProvider> + <DisplayName>HTTP Request Technical Profiles</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="ValidateAccessCodeViaHttp"> + <DisplayName>Check that the user has entered a valid access code by using Claims Transformations</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="ServiceUrl">https://custompolicyapi.azurewebsites.net/validate-accesscode</Item> + <Item Key="SendClaimsIn">Body</Item> + <Item Key="AuthenticationType">None</Item> + <Item Key="AllowInsecureAuthInProduction">true</Item> + </Metadata> + <InputClaims> + <InputClaim ClaimTypeReferenceId="accessCode" PartnerClaimType="accessCode" /> + </InputClaims> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + <!--</ClaimsProviders>--> +``` + +From the protocol, you can observe that we configure the Technical Profile to use the *RestfulProvider*. You can also observe the following information it the metadata section: ++- The `ServiceUrl` represents the API endpoint. Its value is `https://custompolicyapi.azurewebsites.net/validate-accesscode`. If you deployed your Node.js app using an alternative method, make sure to update the endpoint value. ++- `SendClaimsIn` specifies how the input claims are sent to the RESTful claims provider. Possible values: `Body (default)`, `Form`, `Header`, `Url` or `QueryString`. When you use `Body`, such as in this article, you invoke the *POST* HTTP verb, and the data you send to the API if formatted as key, value pairs in the body of the request. Learn [how to invoke the *GET* HTTP verb, and pass data as query string](restful-technical-profile.md#metadata). ++- `AuthenticationType` specifies the type of authentication that the RESTful claims provider performs. Our RESTful claims provider calls an unprotected endpoint, so we set our `AuthenticationType` to *None*. If you set authentication type to `Bearer`, you need to add a *CryptographicKeys* element, which specifies the storage for your access token. Learn more about [the types of authentication that the RESTful claims provider supports](restful-technical-profile.md#metadata). ++- The *PartnerClaimType* attribute in the `InputClaim` specifies how you'll receive your data in the API. + +### Step 2.2 - Update validation technical profile ++In [Create branching in user journey by using Azure AD B2C custom policy](custom-policies-series-branch-user-journey.md), you validated the *accessCode* by using a claims transformation. In this article, you validate the *accessCode* by making an HTTP call to an external service. So, you'll need to update your custom policy to reflect the new approach. ++Locate the *AccessCodeInputCollector* technical profile, and update the *ValidationTechnicalProfile* element's *ReferenceId* to *ValidateAccessCodeViaHttp*: ++from: ++```xml + <ValidationTechnicalProfile ReferenceId="CheckAccessCodeViaClaimsTransformationChecker"/> +``` +to: ++```xml + <ValidationTechnicalProfile ReferenceId="ValidateAccessCodeViaHttp"/> +``` +At this point, the Technical Profile with `Id` *CheckAccessCodeViaClaimsTransformationChecker* isn't needed, and can be removed. +++## Step 3 - Upload custom policy file ++Make sure your Node.js app is running, and then follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file) to upload your policy file. If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. ++## Step 4 - Test the custom policy ++Follow the steps in [Test the custom policy](custom-policies-series-validate-user-input.md#step-6test-the-custom-policy) to test your custom policy: ++1. For **Account Type**, select **Personal Account** +1. Enter the rest of the details as required, and then select **Continue**. You'll see a new screen. +1. For **Access Code**, enter *88888*, and then select **Continue**. After the policy finishes execution, you're redirected to `https://jwt.ms`, and you see a decoded JWT token. If you repeat the procedure, and enter a different **Access Code**, other than *88888*, you'll see an error, **The access code you entered is incorrect. Please try again.** ++## Step 5 - Enable debug mode ++In development, you may want to see detailed errors sent by the API, such as *developerMessage* and *moreInfo*. In this case, you need to enable debug mode in your RESTful technical provider. ++1. Locate your *ValidateAccessCodeViaHttp* technical provider, and add the following item in the technical provider's `metadata`: ++ ```xml + <Item Key="DebugMode">true</Item> + ``` +1. Save the changes and [upload your policy file](#step-3upload-custom-policy-file). ++1. [Test your custom policy](#step-4test-the-custom-policy). Make sure you use a wrong input for your **Access Code**. You'll see an error similar to the one shown in the screenshot below. +++ :::image type="content" source="media/custom-policies-series-call-rest-api/screenshot-error-enable-debug-mode.png" alt-text="A screenshot error when you enable debug mode."::: + +## Handle complex request JSON payloads ++If the REST API that you call requires you to send a complex JSON payload, you can create the payload by using [GenerateJson JSON claims transformations](json-transformations.md#generatejson). Once you generate the payload, you can then [use `ClaimUsedForRequestPayload` metadata](restful-technical-profile.md#send-a-json-payload) option to the name of the claim containing the JSON payload. ++For example, use the following claims transformation to generate a JSON payload: ++```xml + <ClaimsTransformation Id="GenerateRequestBodyClaimsTransformation" TransformationMethod="GenerateJson"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="customerEntity.email" /> + <InputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="customerEntity.userObjectId" /> + <InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="customerEntity.firstName" /> + <InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="customerEntity.lastName" /> + <InputClaim ClaimTypeReferenceId="accessCode" TransformationClaimType="customerEntity.accessCode" /> + </InputClaims> + <InputParameters> + <InputParameter Id="customerEntity.role.name" DataType="string" Value="Administrator" /> + <InputParameter Id="customerEntity.role.id" DataType="long" Value="1" /> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="requestBodyPayload" TransformationClaimType="outputClaim" /> + </OutputClaims> + </ClaimsTransformation> +``` ++The ClaimsTransformation generates the following JSON object: ++```json +{ + "customerEntity":{ + "email":"john.s@contoso.com", + "userObjectId":"01234567-89ab-cdef-0123-456789abcdef", + "firstName":"John", + "lastName":"Smith", + "accessCode":"88888", + "role":{ + "name":"Administrator", + "id": 1 + } + } +} +``` ++Then, update the *Metadata*, *InputClaimsTransformations*, and *InputClaims* of your RESTful technical provider as shown below: ++```xml + <Metadata> + <Item Key="ClaimUsedForRequestPayload">requestBodyPayload</Item> + <!--Other Metadata items --> + </Metadata> + + <!--Execute your InputClaimsTransformations to generate your request Payload--> + <InputClaimsTransformations> + <InputClaimsTransformation ReferenceId="GenerateRequestBodyClaimsTransformation" /> + </InputClaimsTransformations> + + <InputClaims> + <InputClaim ClaimTypeReferenceId="requestBodyPayload" /> + </InputClaims> +``` ++## Next steps ++Next, learn: ++- About [JSON claims transformations](json-transformations.md). + +- About [RESTful technical profile](restful-technical-profile.md). ++- How to [Create and read a user account by using Azure Active Directory B2C custom policy](custom-policies-series-store-user.md) |
active-directory-b2c | Custom Policies Series Collect User Input | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-collect-user-input.md | + + Title: Collect and manipulate user inputs by using Azure AD B2C custom policy ++description: Learn how to collect user inputs from a user and manipulate them by using Azure Active Directory B2C custom policy ++++++++ Last updated : 01/30/2023++++++# Collect and manipulate user inputs by using Azure Active Directory B2C custom policy ++Azure Active Directory B2C (Azure AD B2C) custom policy custom policies allows you to collect user inputs. You can then use inbuilt methods to manipulate the user inputs. ++In this article, you'll learn how to write a custom policy that collects user inputs via a graphical user interface. You'll then access the inputs, process then, and finally return them as claims in a JWT token. To complete this task, you'll: ++- Declare claims. A claim provides temporary storage of data during an Azure AD B2C policy execution. It can store information about the user, such as first name, last name, or any other claim obtained from the user or other systems. You can learn more about claims in the [Azure AD B2C custom policy overview](custom-policy-overview.md#claims). ++- Define technical profiles. A technical profile provides an interface to communicate with different types of parties. For example, it allows you to interact with the user to collect data. ++- Configure claims transformations, which you use to manipulate the claims you declare. ++- Configure content definitions. A content definition defines the user interface to load. Later you can [customize the user interface](customize-ui.md) by providing your own customized HTML content. ++- Configure and show user interfaces to the user by using Self-Asserted Technical Profiles and DisplayClaims. ++- Call Technical Profiles in a given sequence by using Orchestration Steps. ++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. +- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Write your first Azure AD B2C custom policy - Hello World!](custom-policies-series-hello-world.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++## Step 1 - Declare claims ++Declare additional claims alongside *objectId* and *message*: ++1. In VS Code, open the `ContosoCustomPolicy.XML` file. ++1. In the `ClaimsSchema` section, add the following [ClaimType](claimsschema.md) declarations: ++ ```xml + <ClaimType Id="givenName"> + <DisplayName>Given Name</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your given name (also known as first name).</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + + <ClaimType Id="surname"> + <DisplayName>Surname</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your surname (also known as family name or last name).</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + <ClaimType Id="displayName"> + <DisplayName>Display Name</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your display name.</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + ``` ++ We've declared three Claim Types, *givenName*, *surname*, and *displayName*. These declarations include `DataType`, `UserInputType` and `DisplayName` elements: ++- **DataType** specifies the data type of the value that the claims hold. Learn more about the data types that the [DataType elements supports](claimsschema.md#datatype). +- **UserInputType** specifies the UI control that appears on the user interface if you want to collect the value of the claim from the user. Learn more about the user [input types that Azure AD B2C supports](claimsschema.md#userinputtype). +- **DisplayName** specifies the label for the UI control that appears on the user interface if you want to collect the value of the claim from the user. +++## Step 2 - Define claims transformations ++A [ClaimsTransformation](claimstransformations.md) contains a function that you use to convert a given claim into another one. For instance, you can change a string claim from lower case to upper case. Learn more about [Claims transformations supported by Azure AD B2C](claimstransformations.md#claims-transformations-reference). ++1. In the `ContosoCustomPolicy.XML` file, add a `<ClaimsTransformations>` element as a child of the `BuildingBlocks` section. + ```xml + <ClaimsTransformations> + + </ClaimsTransformations> + ``` ++1. Add the following code inside the `ClaimsTransformations` element: ++ ```xml + <ClaimsTransformation Id="GenerateRandomObjectIdTransformation" TransformationMethod="CreateRandomString"> + <InputParameters> + <InputParameter Id="randomGeneratorType" DataType="string" Value="GUID"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> + + <ClaimsTransformation Id="CreateDisplayNameTransformation" TransformationMethod="FormatStringMultipleClaims"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputClaim1"/> + <InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputClaim2"/> + </InputClaims> + <InputParameters> + <InputParameter Id="stringFormat" DataType="string" Value="{0} {1}"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> + + <ClaimsTransformation Id="CreateMessageTransformation" TransformationMethod="FormatStringClaim"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="inputClaim"/> + </InputClaims> + <InputParameters> + <InputParameter Id="stringFormat" DataType="string" Value="Hello {0}"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="message" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> + ``` ++ We've configured three claims transformations: + - *GenerateRandomObjectIdTransformation* generates a random string as specified by the *CreateRandomString* method. The *objectId* claim is updated with the generated string as specified by the `OutputClaim` element. + + - *CreateDisplayNameTransformation* concatenates *givenName* and *surname* to form *displayName*. + + - *CreateMessageTransformation* concatenates *Hello* and *displayName* to form *message*. ++## Step 3 - Configure content definitions ++[ContentDefinitions](contentdefinitions.md) allow you to specify URL to HTML templates that control the layout of the web pages you show to your users. You can specify specific user interfaces for each step, such as sign-in or sign-up, password reset, or error pages. ++To add content definition, add the following code in `BuildingBlocks` section of the `ContosoCustomPolicy.XML` file: ++```xml + <ContentDefinitions> + <ContentDefinition Id="SelfAssertedContentDefinition"> + <LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri> + <RecoveryUri>~/common/default_page_error.html</RecoveryUri> + <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.7</DataUri> + </ContentDefinition> + </ContentDefinitions> +``` ++## Step 4 - Configure technical profiles ++In a custom policy, a [TechnicalProfile](technicalprofiles.md) is the element that implements functionality. Now that you've defined Claims and Claims Transformations, you need Technical Profiles to execute your definitions. A technical profile is declared inside the `ClaimsProvider` elements. ++Azure AD B2C provides a set of technical profiles. Each technical profile performs a specific role. For instance, you use a [REST technical profile](restful-technical-profile.md) to make an HTTP call to a service endpoint. You can use a claims transformation technical profile to execute the operation you define in a Claims Transformation. Learn more about the [types of technical profiles](technicalprofiles.md) that Azure AD B2C custom policies provide. ++### Set values for your claims + +To set values for *objectId*, *displayName* and *message* claims, you configure a technical profile that executes the *GenerateRandomObjectIdTransformation*, *CreateDisplayNameTransformation*, and *CreateMessageTransformation* claims transformations. The claims transformations are executed by the order defined in the `OutputClaimsTransformations` element. For example, it first creates the display name, then the message. ++1. Add the following `ClaimsProvider` as a child of the `ClaimsProviders` section. + + ```xml + <ClaimsProvider> + + <DisplayName>Technical Profiles to generate claims</DisplayName> + </ClaimsProvider> + + ``` +1. To set values for *objectId*, *displayName* and *message* claims, add the following code inside the `ClaimsProvider` element you just created: + + ```xml + <!--<ClaimsProvider>--> + <TechnicalProfiles> + <TechnicalProfile Id="ClaimGenerator"> + <DisplayName>Generate Object ID, displayName and message Claims Technical Profile.</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId"/> + <OutputClaim ClaimTypeReferenceId="displayName"/> + <OutputClaim ClaimTypeReferenceId="message"/> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="GenerateRandomObjectIdTransformation"/> + <OutputClaimsTransformation ReferenceId="CreateDisplayNameTransformation"/> + <OutputClaimsTransformation ReferenceId="CreateMessageTransformation"/> + </OutputClaimsTransformations> + </TechnicalProfile> + </TechnicalProfiles> + <!--</ClaimsProvider>--> + ``` ++### Collect user inputs ++You generate the *displayName* claim from *givenName* and *surname*, so you need to collect then as user inputs. To collect a user input, you use a type of technical profile called [Self-Asserted](self-asserted-technical-profile.md). When you configure a self-asserted technical profile, you need to reference the content definitions as self-asserted technical profile is responsible for displaying a user interface. ++1. Add the following `ClaimsProvider` as a child of the `ClaimsProviders` section. + + ```xml + <ClaimsProvider> + + <DisplayName>Technical Profiles to collect user's details </DisplayName> + </ClaimsProvider> + ``` ++1. Add the following code inside the `ClaimsProvider` element you just created: ++ ```xml + <TechnicalProfiles> + <TechnicalProfile Id="UserInformationCollector"> + <DisplayName>Collect User Input Technical Profile</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <Metadata> + <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item> + </Metadata> + <DisplayClaims> + <DisplayClaim ClaimTypeReferenceId="givenName" Required="true"/> + <DisplayClaim ClaimTypeReferenceId="surname" Required="true"/> + </DisplayClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="givenName"/> + <OutputClaim ClaimTypeReferenceId="surname"/> + </OutputClaims> + </TechnicalProfile> + </TechnicalProfiles> + ``` ++ Notice the two display claims for the *givenName* and *surname* claims. Both of the claims are marked as required, so the user must enter the values before they submit the form displayed to them. The claims are displayed on the screen in the order defined in the *DisplayClaims* element such as, the **Given Name** and then the **Surname**. ++## Step 5 - Define user journeys ++You use user journeys to define order in which the technical profiles are called. You use the `OrchestrationSteps` element to specify the steps in a user journey. ++Replace the existing contents of the `HelloWorldJourney` User Journey with the following code: ++```xml + <OrchestrationSteps> + <OrchestrationStep Order="1" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="2" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="ClaimGenerator"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/> + </OrchestrationSteps> +``` ++According to the orchestration steps, we collect user inputs, set values for *objectId*, *displayName* and *message* claims, and finally send the Jwt token. ++## Step 6 - Update relying party ++Replace the contents of the `OutputClaims` element of the `RelyingParty` section with the following code: ++```xml + <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/> + <OutputClaim ClaimTypeReferenceId="displayName"/> + <OutputClaim ClaimTypeReferenceId="message"/> +``` ++After you complete [step 6](#step-6update-relying-party), the `ContosoCustomPolicy.XML` file should look similar to the following code: ++```xml +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<TrustFrameworkPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" + PolicySchemaVersion="0.3.0.0" TenantId="yourtenant.onmicrosoft.com" + PolicyId="B2C_1A_ContosoCustomPolicy" + PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_ContosoCustomPolicy"> + + <BuildingBlocks> + <ClaimsSchema> + <ClaimType Id="objectId"> + <DisplayName>unique object Id for subject of the claims being returned</DisplayName> + <DataType>string</DataType> + </ClaimType> + <ClaimType Id="message"> + <DisplayName>Will hold Hello World message</DisplayName> + <DataType>string</DataType> + </ClaimType> ++ <ClaimType Id="givenName"> + <DisplayName>Given Name</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your given name (also known as first name).</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + <ClaimType Id="surname"> + <DisplayName>Surname</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your surname (also known as family name or last name).</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + <ClaimType Id="displayName"> + <DisplayName>Display Name</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your display name.</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + </ClaimsSchema> + <ClaimsTransformations> + <ClaimsTransformation Id="GenerateRandomObjectIdTransformation" TransformationMethod="CreateRandomString"> + <InputParameters> + <InputParameter Id="randomGeneratorType" DataType="string" Value="GUID"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> ++ <ClaimsTransformation Id="CreateDisplayNameTransformation" TransformationMethod="FormatStringMultipleClaims"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputClaim1"/> + <InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputClaim2"/> + </InputClaims> + <InputParameters> + <InputParameter Id="stringFormat" DataType="string" Value="{0} {1}"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> ++ <ClaimsTransformation Id="CreateMessageTransformation" TransformationMethod="FormatStringClaim"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="inputClaim"/> + </InputClaims> + <InputParameters> + <InputParameter Id="stringFormat" DataType="string" Value="Hello {0}"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="message" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> + </ClaimsTransformations> + <ContentDefinitions> + <ContentDefinition Id="SelfAssertedContentDefinition"> + <LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri> + <RecoveryUri>~/common/default_page_error.html</RecoveryUri> + <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.7</DataUri> + </ContentDefinition> + </ContentDefinitions> + </BuildingBlocks> + <!--Claims Providers Here--> + <ClaimsProviders> + <ClaimsProvider> + <DisplayName>Token Issuer</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="JwtIssuer"> + <DisplayName>JWT Issuer</DisplayName> + <Protocol Name="None"/> + <OutputTokenFormat>JWT</OutputTokenFormat> + <Metadata> + <Item Key="client_id">{service:te}</Item> + <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item> + <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item> + </Metadata> + <CryptographicKeys> + <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/> + <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer"/> + </CryptographicKeys> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> ++ <ClaimsProvider> + <DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13"> + <DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName> + <Protocol Name="None"/> + <Metadata> + <Item Key="url">{service:te}</Item> + </Metadata> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> ++ <ClaimsProvider> + <DisplayName>Claim Generator Technical Profiles</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="ClaimGenerator"> + <DisplayName>Generate Object ID, displayName and message Claims Technical Profile.</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId"/> + <OutputClaim ClaimTypeReferenceId="displayName"/> + <OutputClaim ClaimTypeReferenceId="message"/> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="GenerateRandomObjectIdTransformation"/> + <OutputClaimsTransformation ReferenceId="CreateDisplayNameTransformation"/> + <OutputClaimsTransformation ReferenceId="CreateMessageTransformation"/> + </OutputClaimsTransformations> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> ++ <ClaimsProvider> + <DisplayName>Technical Profiles to collect user's details</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="UserInformationCollector"> + <DisplayName>Collect User Input Technical Profile</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <Metadata> + <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item> + </Metadata> + <DisplayClaims> + <DisplayClaim ClaimTypeReferenceId="givenName" Required="true"/> + <DisplayClaim ClaimTypeReferenceId="surname" Required="true"/> + </DisplayClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="givenName"/> + <OutputClaim ClaimTypeReferenceId="surname"/> + </OutputClaims> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + </ClaimsProviders> ++ <UserJourneys> + <UserJourney Id="HelloWorldJourney"> + <OrchestrationSteps> + <OrchestrationStep Order="1" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="2" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="ClaimGenerator"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/> + </OrchestrationSteps> + </UserJourney> + </UserJourneys> ++ <RelyingParty><!-- + Relying Party Here that's your policyΓÇÖs entry point + Specify the User Journey to execute + Specify the claims to include in the token that is returned when the policy runs + --> + <DefaultUserJourney ReferenceId="HelloWorldJourney"/> + <TechnicalProfile Id="HelloWorldPolicyProfile"> + <DisplayName>Hello World Policy Profile</DisplayName> + <Protocol Name="OpenIdConnect"/> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/> + <OutputClaim ClaimTypeReferenceId="displayName"/> + <OutputClaim ClaimTypeReferenceId="message"/> + </OutputClaims> + <SubjectNamingInfo ClaimType="sub"/> + </TechnicalProfile> + </RelyingParty> +</TrustFrameworkPolicy> +``` +If you haven't already done so, replace `yourtenant` with the subdomain part of your tenant name, such as `contoso`. Learn how to [Get your tenant name](tenant-management-read-tenant-name.md#get-your-tenant-name). ++## Step 3 - Upload custom policy file ++Follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file). If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. +++## Step 4 - Test the custom policy ++1. Under **Custom policies**, select **B2C_1A_CONTOSOCUSTOMPOLICY**. +1. For **Select application** on the overview page of the custom policy, select the web application such as *webapp1* that you previously registered. Make sure that the **Select reply URL** value is set to`https://jwt.ms`. +1. Select **Run now** button. +1. Enter **Given Name** and **Surname**, and then select **Continue**. ++ :::image type="content" source="media/custom-policies-series-collect-user-input/screenshot-of-accepting-user-inputs-in-custom-policy.png" alt-text="screenshot of accepting user inputs in custom policy."::: ++After the policy finishes execution, you're redirected to `https://jwt.ms`, and you see a decoded JWT token. It looks similar to the following JWT token snippet: ++```json + { + "typ": "JWT", + "alg": "RS256", + "kid": "pxLOMWFg...." + }.{ + ... + "sub": "c7ae4515-f7a7....", + ... + "acr": "b2c_1a_contosocustompolicy", + ... + "name": "Maurice Paulet", + "message": "Hello Maurice Paulet" + }.[Signature] +``` ++## Next steps ++Next, learn: ++- About [types of Technical Profiles](technicalprofiles.md#types-of-technical-profiles) in Azure AD B2C's custom policies. ++- How to [Validate user inputs by using custom policy](custom-policies-series-validate-user-input.md). |
active-directory-b2c | Custom Policies Series Hello World | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-hello-world.md | + + Title: Write your first Azure AD B2C custom policy - Hello World! ++description: Learn how to write your first custom policy. A custom that shows of returns Hello World message. ++++++++ Last updated : 01/30/2023++++++# Write your first Azure Active Directory B2C custom policy - Hello World! ++In your applications, you can use user flows that enable users to sign up, sign in, or manage their profile. When user flows don't cover all your business specific needs, you use [custom policies](custom-policy-overview.md). ++While you can use pre-made custom policy [starter pack](https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack) to write custom policies, it's important for you understand how a custom policy is built. In this article, you'll learn how to create your first custom policy from scratch. ++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. +++## Step 1 - Configure the signing and encryption keys ++If you haven't already done so, create the following encryption keys. To automate the walk-through below, visit the [IEF Setup App](https://b2ciefsetupapp.azurewebsites.net/) and follow the instructions: ++ 1. Use the steps in [Add signing and encryption keys for Identity Experience Framework applications](tutorial-create-user-flows.md?pivots=b2c-custom-policy#add-signing-and-encryption-keys-for-identity-experience-framework-applications) to create the signing key. ++ 1. Use the steps in [Add signing and encryption keys for Identity Experience Framework applications](tutorial-create-user-flows.md?pivots=b2c-custom-policy#add-signing-and-encryption-keys-for-identity-experience-framework-applications) to create the encryption key. ++## Step 2 - Build the custom policy file ++1. In VS Code, create and open the file `ContosoCustomPolicy.XML`. ++1. In the `ContosoCustomPolicy.XML` file, add the following code: + + ```xml + <?xml version="1.0" encoding="UTF-8" standalone="yes"?> + <TrustFrameworkPolicy + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" + PolicySchemaVersion="0.3.0.0" + TenantId="yourtenant.onmicrosoft.com" + PolicyId="B2C_1A_ContosoCustomPolicy" + PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_ContosoCustomPolicy"> + + <BuildingBlocks> + <!-- Building Blocks Here--> + <BuildingBlocks> + + <ClaimsProviders> + <!-- Claims Providers Here--> + </ClaimsProviders> + + <UserJourneys> + <!-- User Journeys Here--> + </UserJourneys> + + <RelyingParty> + <!-- + Relying Party Here that's your policyΓÇÖs entry point + Specify the User Journey to execute + Specify the claims to include in the token that is returned when the policy runs + --> + </RelyingParty> + </TrustFrameworkPolicy> ++ ``` + Replace `yourtenant` with the subdomain part of your tenant name, such as `contoso`. Learn how to [Get your tenant name](tenant-management-read-tenant-name.md#get-your-tenant-name). ++ The XML elements define the top-level `TrustFrameworkPolicy` element of a policy file with its policy ID and tenant name. The TrustFrameworkPolicy element contains other XML elements that you'll use in this series. ++1. To declare a claim, add the following code in `BuildingBlocks` section of the `ContosoCustomPolicy.XML` file: ++ ```xml + <ClaimsSchema> + <ClaimType Id="objectId"> + <DisplayName>unique object Id for subject of the claims being returned</DisplayName> + <DataType>string</DataType> + </ClaimType> + <ClaimType Id="message"> + <DisplayName>Will hold Hello World message</DisplayName> + <DataType>string</DataType> + </ClaimType> + </ClaimsSchema> + ``` + A [claim](claimsschema.md#claimtype) is like a variable. The claim's declaration also shows the claim's [data type](claimsschema.md#datatype). ++1. In the `ClaimsProviders` section of the `ContosoCustomPolicy.XML` file, add the following code: ++ ```xml + <ClaimsProvider> + <DisplayName>Token Issuer</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="JwtIssuer"> + <DisplayName>JWT Issuer</DisplayName> + <Protocol Name="None" /> + <OutputTokenFormat>JWT</OutputTokenFormat> + <Metadata> + <Item Key="client_id">{service:te}</Item> + <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item> + <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item> + </Metadata> + <CryptographicKeys> + <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" /> + <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" /> + </CryptographicKeys> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> ++ <ClaimsProvider> + <!-- The technical profile(s) defined in this section is required by the framework to be included in all custom policies. --> + <DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13"> + <DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName> + <Protocol Name="None" /> + <Metadata> + <Item Key="url">{service:te}</Item> + </Metadata> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + ``` + + We've declared a JWT Token Issuer. In the `CryptographicKeys` section, if you used different names to configure the signing and encryption keys in [step 1](#step-1configure-the-signing-and-encryption-keys), make sure you use the correct value for the `StorageReferenceId`. ++1. In the `UserJourneys` section of the `ContosoCustomPolicy.XML` file, add the following code: ++ ```xml + <UserJourney Id="HelloWorldJourney"> + <OrchestrationStep Order="1" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> + </UserJourney> + ``` + + We've added a [UserJourney](userjourneys.md). The user journey specifies the business logic the end user goes through as Azure AD B2C processes a request. This user journey has only one step that issues a JTW token with the claims that you'll define in the next step. ++1. In the `RelyingParty` section of the `ContosoCustomPolicy.XML` file, add the following code: ++ ```xml + <DefaultUserJourney ReferenceId="HelloWorldJourney"/> + <TechnicalProfile Id="HelloWorldPolicyProfile"> + <DisplayName>Hello World Policy Profile</DisplayName> + <Protocol Name="OpenIdConnect" /> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" DefaultValue="abcd-1234-efgh-5678-ijkl-etc."/> + <OutputClaim ClaimTypeReferenceId="message" DefaultValue="Hello World!"/> + </OutputClaims> + <SubjectNamingInfo ClaimType="sub" /> + </TechnicalProfile> + ``` ++ The [RelyingParty](relyingparty.md) section is the entry point to your policy. It specifies the [UserJourney](userjourneys.md) to execute and the claims to include in the token that is returned when the policy runs. ++After you complete [step 2](#step-2build-the-custom-policy-file), the `ContosoCustomPolicy.XML` file should look similar to the following code: ++```xml + <?xml version="1.0" encoding="UTF-8" standalone="yes"?> + <TrustFrameworkPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" PolicySchemaVersion="0.3.0.0" TenantId="Contosob2c2233.onmicrosoft.com" PolicyId="B2C_1A_ContosoCustomPolicy" PublicPolicyUri="http://Contosob2c2233.onmicrosoft.com/B2C_1A_ContosoCustomPolicy"> + <BuildingBlocks> + <ClaimsSchema> + <ClaimType Id="objectId"> + <DisplayName>unique object Id for subject of the claims being returned</DisplayName> + <DataType>string</DataType> + </ClaimType> + <ClaimType Id="message"> + <DisplayName>Will hold Hello World message</DisplayName> + <DataType>string</DataType> + </ClaimType> + </ClaimsSchema> + </BuildingBlocks> + <ClaimsProviders><!--Claims Providers Here--> + <ClaimsProvider> + <DisplayName>Token Issuer</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="JwtIssuer"> + <DisplayName>JWT Issuer</DisplayName> + <Protocol Name="None"/> + <OutputTokenFormat>JWT</OutputTokenFormat> + <Metadata> + <Item Key="client_id">{service:te}</Item> + <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item> + <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item> + </Metadata> + <CryptographicKeys> + <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/> + <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer"/> + </CryptographicKeys> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + + <ClaimsProvider> + <DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13"> + <DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName> + <Protocol Name="None" /> + <Metadata> + <Item Key="url">{service:te}</Item> + </Metadata> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + </ClaimsProviders> + <UserJourneys> + <UserJourney Id="HelloWorldJourney"> + <OrchestrationSteps> + <OrchestrationStep Order="1" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> + </OrchestrationSteps> + </UserJourney> + </UserJourneys> + <RelyingParty><!-- + Relying Party Here that's your policyΓÇÖs entry point + Specify the User Journey to execute + Specify the claims to include in the token that is returned when the policy runs + --> + <DefaultUserJourney ReferenceId="HelloWorldJourney"/> + <TechnicalProfile Id="HelloWorldPolicyProfile"> + <DisplayName>Hello World Policy Profile</DisplayName> + <Protocol Name="OpenIdConnect"/> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" DefaultValue="abcd-1234-efgh-5678-ijkl-etc."/> + <OutputClaim ClaimTypeReferenceId="message" DefaultValue="Hello World!"/> + </OutputClaims> + <SubjectNamingInfo ClaimType="sub"/> + </TechnicalProfile> + </RelyingParty> + </TrustFrameworkPolicy> +``` + +## Step 3 - Upload custom policy file ++1. Sign in to the [Azure portal](https://portal.azure.com). +1. Make sure you're using the directory that contains your Azure AD B2C tenant: + 1. Select the **Directories + subscriptions** icon in the portal toolbar. + 1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. In the Azure portal, search for and select **Azure AD B2C**. +1. In the left menu, under **Policies**, select **Identity Experience Framework**. +1. Select **Upload custom policy**, browse select and then upload the `ContosoCustomPolicy.XML` file. +++After you upload the file, Azure AD B2C adds the prefix `B2C_1A_`, so the names looks similar to **B2C_1A_CONTOSOCUSTOMPOLICY**. +++## Step 4 - Test the custom policy ++1. Under **Custom policies**, select **B2C_1A_CONTOSOCUSTOMPOLICY**. +1. For **Select application** on the overview page of the custom policy, select the web application such as *webapp1* that you previously registered. Make sure that the **Select reply URL** value is set to`https://jwt.ms`. +1. Select **Run now** button. ++After the policy finishes execution, you're redirected to `https://jwt.ms`, and you see a decoded JWT token. It looks similar to the following JWT token snippet: ++```json + { + "typ": "JWT", + "alg": "RS256", + "kid": "pxLOMWFg...." + }.{ + ... + "sub": "abcd-1234-efgh-5678-ijkl-etc.", + ... + "acr": "b2c_1a_contosocustompolicy", + ... + "message": "Hello World!" + }.[Signature] +``` ++Notice the `message` and `sub` claims, which we set as output claims](relyingparty.md#outputclaims) in the `RelyingParty` section. ++## Next steps ++In this article, you learned and used four sections that are included in an Azure AD B2C custom policy. These sections are added as child elements the `TrustFrameworkPolicy` root element: ++> [!div class="checklist"] +> - BuildingBlocks +> - ClaimsProviders +> - UserJourneys +> - RelyingParty +++Next, learn: ++- How to [collect and use user inputs by using custom policy](custom-policies-series-collect-user-input.md). ++- About custom policy [claims overview](custom-policy-overview.md#claims). ++- How to [declare a custom policy claim](claimsschema.md). ++- About custom policy [claims data type](claimsschema.md#datatype). ++- About custom policy [user input types](claimsschema.md#userinputtype). |
active-directory-b2c | Custom Policies Series Install Xml Extensions | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-install-xml-extensions.md | + + Title: Validate custom policy files by using TrustFrameworkPolicy schema ++description: Learn how to validate custom policy files by using TrustFrameworkPolicy schema and other XML extensions for Visual Studio code. You also learn to navigate custom policy file by using Azure AD B2C extension. ++++++++ Last updated : 01/30/2023++++++# Validate custom policy files by using TrustFrameworkPolicy schema ++You can improve your productivity when editing or writing custom policy files by validating your files before you upload them. You can let Azure Active Directory B2C (Azure AD B2C) to validate the XML policy files when you upload them, but most errors cause the upload to fail. An example of invalid policy file is improperly formatted XML. ++It's essential to use a good XML editor such as [Visual Studio Code (VS Code)](https://code.visualstudio.com/). We recommend using VS Code as it allows you to install XML extension, such as [XML Language Support by Red Hat](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml). A good XML editor together with extra XML extension allows you to color-codes content, pre-fills common terms, keeps XML elements indexed, and can validate against an XML schema. +++To validate custom policy files, we provide a custom policy XML schema. You can download the schema by using the link `https://raw.githubusercontent.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/master/TrustFrameworkPolicy_0.3.0.0.xsd` or refer to it from your editor by using the same link. You can also use Azure AD B2C extension for VS Code to quickly navigate through Azure AD B2C policy files, and many other functions. Lean more about [Azure AD B2C extension for VS Code](https://marketplace.visualstudio.com/items?itemName=AzureADB2CTools.aadb2c). ++In this article, you'll learn how to: ++- Use custom policy XML schema to validate policy files. +- Use Azure AD B2C extension for VS Code to quickly navigate through your policy files. ++## Prerequisites ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- A custom policy file such as the one we used in [Validate user inputs by using Azure AD B2C custom policy](custom-policies-series-validate-user-input.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++## Use TrustFrameworkPolicy schema ++TrustFrameworkPolicy schema is a custom policy XML schema that allows you to validate policy files: ++1. Install [XML extension support by Red Hat](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml) in your VS Code editor ++1. Follow the steps in [Troubleshoot policy validity](troubleshoot.md?pivots=b2c-custom-policy#troubleshoot-policy-validity) to set up fileAssociations your VS Code editor. The instructions also include the procedure to validate your policy file. ++## Use Azure AD B2C extension ++Azure AD B2C extension allows you to understand the organization of your policy files easily. For example, the custom policy explorer allows you to see the custom policy elements you've used and to move to them quickly. ++1. Install [Azure AD B2C extension](https://marketplace.visualstudio.com/items?itemName=AzureADB2CTools.aadb2c) in your VS Code editor ++1. Follow the guidance provided in [Azure AD B2C extension](https://marketplace.visualstudio.com/items?itemName=AzureADB2CTools.aadb2c) to learn how to use Azure AD B2C extension. ++> [!NOTE] +> The community has developed the VS Code extension for Azure AD B2C to help identity developers. The extension is not supported by Microsoft and is made available strictly as-is. ++## Next steps ++Next, learn: ++- How to [Troubleshoot Azure AD B2C custom policies](troubleshoot.md?pivots=b2c-custom-policy). ++- How to make [Call a REST API by using Azure AD B2C custom policy](custom-policies-series-call-rest-api.md). |
active-directory-b2c | Custom Policies Series Overview | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-overview.md | + + Title: Create and run your own custom policies in Azure Active Directory B2C ++description: Learn how to create and run your own custom policies in Azure Active Directory B2C. Learn how to create Azure Active Directory B2C custom policies from scratch in a how-to guide series. ++++++++ Last updated : 01/30/2023++++++# Create and run your own custom policies in Azure Active Directory B2C ++In Azure Active Directory B2C (Azure AD B2C), you can create user experiences by using [user flows or custom policies](user-flow-overview.md). You use custom policies when you want to create your own user journeys for complex identity experience scenarios that aren't supported by user flows. ++User flows are already customizable such as [changing UI](customize-ui.md), [customizing language](language-customization.md) and using [custom attributes](user-flow-custom-attributes.md). However, these customizations might not cover all your business specific needs, which is the reason why you need custom policies. ++While you can use pre-made [custom policy starter pack](/tutorial-create-user-flows.md?pivots=b2c-custom-policy#custom-policy-starter-pack), it's important for you understand how custom policy is built from scratch. In this how-to guide series, you'll learn what you need to understand for you to customize the behavior of your user experience by using custom policies. At the end of this how-to guide series, you should be able to read and understand existing custom policies or write your own from scratch. ++## Prerequisites ++- You already understand how to use Azure AD B2C user flows. If you haven't already used user flows, [learn how to Create user flows and custom policies in Azure Active Directory B2C](tutorial-create-user-flows.md?pivots=b2c-user-flow). This how-to guide series is intended for identity app developers who want to leverage the power of Azure AD B2C custom policies to achieve almost any authentication flow experience. ++## Select an article ++This how-to guide series consists of multiple articles. We recommend that you start this series from the fist article. For each article (except the first one), you're expected to use the custom policy you write in the preceding article. ++|Article | What you'll learn | +||| +|[Write your first Azure Active Directory B2C custom policy - Hello World!](custom-policies-series-hello-world.md) | Write your first Azure AD B2C custom policy. You'll return the message *Hello World!* in the JWT token. | +|[Collect and manipulate user inputs by using Azure AD B2C custom policy](custom-policies-series-collect-user-input.md) | Learn how to collect inputs from users, and how to manipulate them.| +|[Validate user inputs by using Azure Active Directory B2C custom policy](custom-policies-series-validate-user-input.md) | Learn how to validate user inputs by using techniques such as limiting user input options, regular expressions, predicates, and validation technical profiles| +|[Create branching in user journey by using Azure Active Directory B2C custom policy](custom-policies-series-branch-user-journey.md) | Learn how to create different user experiences for different users based on the value of a claim.| +|[Validate custom policy files by using TrustFrameworkPolicy schema](custom-policies-series-install-xml-extensions.md)| Learn how to validate your custom files against a custom policy schema. You also learn how to easily navigate your policy files by using Azure AD B2C Visual Studio Code (VS Code) extension.| +|[Call a REST API by using Azure Active Directory B2C custom policy](custom-policies-series-call-rest-api.md)| Learn how to write a custom policy that integrates with your own RESTful service.| +|[Create and read a user account by using Azure Active Directory B2C custom policy](custom-policies-series-store-user.md)| Learn how to store into and read user details from Azure AD storage by using Azure AD B2C custom policy. You use the Azure Active Directory technical profile.| +|[Set up a sign-up and sign-in flow by using Azure Active Directory B2C custom policy](custom-policies-series-sign-up-or-sign-in.md). | Learn how to configure a sign-up and sign-in flow for a local account(using email and password) by using Azure Active Directory B2C custom policy. You show a user a sign-in interface for them to sign in by using their existing account, but they can create a new account if they don't already have one.| +| [Set up a sign-up and sign-in flow with a social account by using Azure Active Directory B2C custom policy](custom-policies-series-sign-up-or-sign-in-federation.md) | Learn how to configure a sign-up and sign-in flow for a social account, Facebook. You also learn to combine local and social sign-up and sign-in flow.| ++## Next steps ++- Learn about [Azure AD B2C TrustFrameworkPolicy BuildingBlocks](buildingblocks.md) + +- [Write your first Azure Active Directory B2C custom policy - Hello World!](custom-policies-series-hello-world.md) |
active-directory-b2c | Custom Policies Series Sign Up Or Sign In Federation | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-sign-up-or-sign-in-federation.md | + + Title: Set up a sign-up and sign-in flow with a social account by using Azure Active Directory B2C custom policy ++description: Learn how to configure a sign-up and sign-in flow for a social account, Facebook, by using Azure Active Directory B2C custom policy. ++++++++ Last updated : 01/30/2023++++++# Set up a sign-up and sign-in flow with a social account by using Azure Active Directory B2C custom policy ++In [Set up a sign-up and sign-in flow by using Azure Active Directory B2C custom policy](custom-policies-series-sign-up-or-sign-in.md) article, we set up sign-in flow for a local account by using Azure Active Directory B2C (Azure AD B2C). ++In this article, we add a sign-in flow for an external account, such as a social account like Facebook. In this case, Azure AD B2C allows a user to sign in to your application with credentials from an external social identity provider (IdP). ++For local accounts, a user account is uniquely identified by using the `objectId` [user attribute](user-profile-attributes.md). For external IdP, we use `alternativeSecurityId` user attribute though an `objectId` still exists. ++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Set up a sign-up and sign-in flow for local account by using Azure Active Directory B2C custom policy](custom-policies-series-sign-up-or-sign-in.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++++## Step 1 - Create Facebook application ++Use the steps outlined in [Create a Facebook application](identity-provider-facebook.md?pivots=b2c-custom-policy#create-a-facebook-application) to obtain Facebook *App ID* and *App Secret*. Skip the prerequisites and the rest of the steps in the [Set up sign up and sign in with a Facebook account](identity-provider-facebook.md?pivots=b2c-custom-policy) article. ++## Step 2 - Create Facebook policy key ++Use the steps outlined in [Create the Facebook key](identity-provider-facebook.md?pivots=b2c-custom-policy#create-a-policy-key) store a policy key in your Azure AD B2C tenant. Skip the prerequisites and the rest of the steps in the [Set up sign up and sign in with a Facebook account](identity-provider-facebook.md?pivots=b2c-custom-policy) article. ++## Step 3 - Configure sign-in with Facebook ++To configure sign in with Facebook, you need to perform the following steps: ++- Declare more claims +- Define more claims transformations to help with claims manipulations such as creating *AlternativeSecurityId*. +- Configure Facebook claims provider +- Configure Azure AD technical profiles to read and write the social account from and to the Azure AD database. +- Configure a self-asserted technical profile (for accepting additional input from user or updating user details) and its content definition. +++### Step 3.1 - Declare more claims ++In the `ContosoCustomPolicy.XML` file, locate the *ClaimsSchema* section, and then declare more claims by using the following code: ++```xml + <!--<ClaimsSchema>--> + ... + <ClaimType Id="issuerUserId"> + <DisplayName>Username</DisplayName> + <DataType>string</DataType> + <UserHelpText/> + <UserInputType>TextBox</UserInputType> + <Restriction> + <Pattern RegularExpression="^[a-zA-Z0-9]+[a-zA-Z0-9_-]*$" HelpText="The username you provided is not valid. It must begin with an alphabet or number and can contain alphabets, numbers and the following symbols: _ -" /> + </Restriction> + </ClaimType> + + <ClaimType Id="identityProvider"> + <DisplayName>Identity Provider</DisplayName> + <DataType>string</DataType> + <UserHelpText/> + </ClaimType> + + <ClaimType Id="authenticationSource"> + <DisplayName>AuthenticationSource</DisplayName> + <DataType>string</DataType> + <UserHelpText>Specifies whether the user was authenticated at Social IDP or local account.</UserHelpText> + </ClaimType> + + <ClaimType Id="upnUserName"> + <DisplayName>UPN User Name</DisplayName> + <DataType>string</DataType> + <UserHelpText>The user name for creating user principal name.</UserHelpText> + </ClaimType> + + <ClaimType Id="alternativeSecurityId"> + <DisplayName>AlternativeSecurityId</DisplayName> + <DataType>string</DataType> + <UserHelpText/> + </ClaimType> + + <ClaimType Id="mailNickName"> + <DisplayName>MailNickName</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your mail nick name as stored in the Azure Active Directory.</UserHelpText> + </ClaimType> + + <ClaimType Id="newUser"> + <DisplayName>User is new or not</DisplayName> + <DataType>boolean</DataType> + <UserHelpText/> + </ClaimType> + <!--</ClaimsSchema>--> +``` ++### Step 3.2 - Define claims transformations ++In the `ContosoCustomPolicy.XML` file, locate the *ClaimsTransformations* element, and add claims transformations by using the following code: ++ ```xml + <!--<ClaimsTransformations>--> + ... + <ClaimsTransformation Id="CreateRandomUPNUserName" TransformationMethod="CreateRandomString"> + <InputParameters> + <InputParameter Id="randomGeneratorType" DataType="string" Value="GUID" /> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="upnUserName" TransformationClaimType="outputClaim" /> + </OutputClaims> + </ClaimsTransformation> + + <ClaimsTransformation Id="CreateAlternativeSecurityId" TransformationMethod="CreateAlternativeSecurityId"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="issuerUserId" TransformationClaimType="key" /> + <InputClaim ClaimTypeReferenceId="identityProvider" TransformationClaimType="identityProvider" /> + </InputClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="alternativeSecurityId" TransformationClaimType="alternativeSecurityId" /> + </OutputClaims> + </ClaimsTransformation> + + <ClaimsTransformation Id="CreateUserPrincipalName" TransformationMethod="FormatStringClaim"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="upnUserName" TransformationClaimType="inputClaim" /> + </InputClaims> + <InputParameters> + <InputParameter Id="stringFormat" DataType="string" Value="cpim_{0}@{RelyingPartyTenantId}" /> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="userPrincipalName" TransformationClaimType="outputClaim" /> + </OutputClaims> + </ClaimsTransformation> + <!--</ClaimsTransformations>--> + ``` ++We've defined three Claims Transformations, which we use to generate values for *alternativeSecurityId* and *userPrincipalName* claims. These ClaimsTransformations are invoked in the OAuth2 technical profile in [step 3.3](#step-33configure-facebook-claims-provider). ++### Step 3.3 - Configure Facebook claims provider ++To enable users to sign in using a Facebook account, you need to define the account as a claims provider that Azure AD B2C can communicate with through an endpoint. You can define a Facebook account as a claims provider. ++In the `ContosoCustomPolicy.XML` file, locate *ClaimsProviders* element, add a new claims provider by using the following code: ++```xml + <!--<ClaimsProviders>--> + ... + <ClaimsProvider> + <!-- The following Domain element allows this profile to be used if the request comes with domain_hint + query string parameter, e.g. domain_hint=facebook.com --> + <Domain>facebook.com</Domain> + <DisplayName>Facebook</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="Facebook-OAUTH"> + <!-- The text in the following DisplayName element is shown to the user on the claims provider + selection screen. --> + <DisplayName>Facebook</DisplayName> + <Protocol Name="OAuth2" /> + <Metadata> + <Item Key="ProviderName">facebook</Item> + <Item Key="authorization_endpoint">https://www.facebook.com/dialog/oauth</Item> + <Item Key="AccessTokenEndpoint">https://graph.facebook.com/oauth/access_token</Item> + <Item Key="HttpBinding">GET</Item> + <Item Key="UsePolicyInRedirectUri">0</Item> + <Item Key="client_id">facebook-app-id</Item> + <Item Key="scope">email public_profile</Item> + <Item Key="ClaimsEndpoint">https://graph.facebook.com/me?fields=id,first_name,last_name,name,email</Item> + <Item Key="AccessTokenResponseFormat">json</Item> + </Metadata> + <CryptographicKeys> + <Key Id="client_secret" StorageReferenceId="facebook-policy-key" /> + </CryptographicKeys> + <InputClaims /> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="id" /> + <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="first_name" /> + <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="last_name" /> + <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" /> + <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" /> + <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="facebook.com" AlwaysUseDefaultValue="true" /> + <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" /> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" /> + <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" /> + <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" /> + </OutputClaimsTransformations> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + <!--</ClaimsProviders>--> +``` ++Replace: +- `facebook-app-id` with the value of Facebook *appID* you obtained in [step 1](#step-1create-facebook-application). +- `facebook-policy-key` with the name of the Facebook policy key you obtained in [step 2](#step-2create-facebook-policy-key). ++Notice the claims transformations we defined in [step 3.2](#step-32define-claims-transformations) in the *OutputClaimsTransformations* collection. ++### Step 3.4 - Create Azure AD technical profiles ++Just like in sign-in with a local account, you need to configure the [Azure AD Technical Profiles](active-directory-technical-profile.md), which you use to connect to Azure AD storage, to store or read a user social account. ++1. In the `ContosoCustomPolicy.XML` file, locate the *AAD-UserUpdate* technical profile and then add a new technical profile by using the following code: ++ ```xml + <TechnicalProfile Id="AAD-UserWriteUsingAlternativeSecurityId"> + <DisplayName>Azure Active Directory technical profile for handling social accounts</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + + <Metadata> + <Item Key="Operation">Write</Item> + <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item> + </Metadata> + + <CryptographicKeys> + <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" /> + </CryptographicKeys> + <InputClaims> + <InputClaim ClaimTypeReferenceId="alternativeSecurityId" PartnerClaimType="alternativeSecurityId" Required="true" /> + </InputClaims> + <PersistedClaims> + <!-- Required claims --> + <PersistedClaim ClaimTypeReferenceId="alternativeSecurityId" /> + <PersistedClaim ClaimTypeReferenceId="userPrincipalName" /> + <PersistedClaim ClaimTypeReferenceId="mailNickName" DefaultValue="unknown" /> + <PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" /> + + <!-- Optional claims --> + <PersistedClaim ClaimTypeReferenceId="givenName" /> + <PersistedClaim ClaimTypeReferenceId="surname" /> + </PersistedClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" /> + <OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" /> + </OutputClaims> + + </TechnicalProfile> + ``` + We've added a new Azure AD Technical Profile *AAD-UserWriteUsingAlternativeSecurityId* that writes a new social account into Azure AD. ++1. Replace *B2C_1A_TokenSigningKeyContainer* with the token signing key you created in [Configure the signing](custom-policies-series-hello-world.md#step-1configure-the-signing-and-encryption-keys). + +1. In the `ContosoCustomPolicy.XML` file, add another Azure AD technical profile after the *AAD-UserWriteUsingAlternativeSecurityId* Technical Profile by using the following code: ++ ```xml + <TechnicalProfile Id="AAD-UserReadUsingAlternativeSecurityId"> + <DisplayName>Azure Active Directory</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="Operation">Read</Item> + <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item> + </Metadata> + <CryptographicKeys> + <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" /> + </CryptographicKeys> + <InputClaims> + <InputClaim ClaimTypeReferenceId="alternativeSecurityId" PartnerClaimType="alternativeSecurityId" Required="true" /> + </InputClaims> + <OutputClaims> + <!-- Required claims --> + <OutputClaim ClaimTypeReferenceId="objectId" /> + + <!-- Optional claims --> + <OutputClaim ClaimTypeReferenceId="userPrincipalName" /> + <OutputClaim ClaimTypeReferenceId="displayName" /> + <OutputClaim ClaimTypeReferenceId="givenName" /> + <OutputClaim ClaimTypeReferenceId="surname" /> + </OutputClaims> + </TechnicalProfile> + ``` ++ We've added a new Azure AD Technical Profile *AAD-UserReadUsingAlternativeSecurityId* that reads a new social account from Azure AD. It uses `alternativeSecurityId` as a unique identifier for the social account. ++1. Replace *B2C_1A_TokenSigningKeyContainer* with the token signing key you created in [Configure the signing](custom-policies-series-hello-world.md#step-1configure-the-signing-and-encryption-keys). ++### Step 3.5 - Configure content definition ++After a user signs in, you can collect some information from them by using a self-asserted technical profile. So, you need to configure content definition for the self-asserted technical profile. ++In the `ContosoCustomPolicy.XML` file, locate the *ContentDefinitions* element, and then add a new content definition in the `ContentDefinitions` collection by using the following code: ++```xml + <ContentDefinition Id="socialAccountsignupContentDefinition"> + <LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri> + <RecoveryUri>~/common/default_page_error.html</RecoveryUri> + <DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.7</DataUri> + <Metadata> + <Item Key="DisplayName">Collect information from user page alongside those from social Idp.</Item> + </Metadata> + </ContentDefinition> +``` +We use this content definition as a metadata in a self-asserted technical profile on the next step ([step 3.6](#step-36configure-a-self-asserted-technical-profile)). ++### Step 3.6 - Configure a self-asserted technical profile ++The self-asserted technical profile you configure in this step is used to collect more information from the user or update similar information obtained from the social account. ++In the `ContosoCustomPolicy.XML` file, locate the *ClaimsProviders* section, and then add a new claims provider by using the following code: ++```xml + <!--<ClaimsProviders>--> + ... + <ClaimsProvider> + <DisplayName>Self Asserted for social sign in</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="SelfAsserted-Social"> + <DisplayName>Collect more info during social signup</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="ContentDefinitionReferenceId">socialAccountsignupContentDefinition</Item> + </Metadata> + <CryptographicKeys> + <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" /> + </CryptographicKeys> + <InputClaims> + <!-- These claims ensure that any values retrieved in the previous steps (e.g. from an external IDP) are prefilled. + Note that some of these claims may not have any value, for example, if the external IDP did not provide any of + these values, or if the claim did not appear in the OutputClaims section of the IDP. + In addition, if a claim is not in the InputClaims section, but it is in the OutputClaims section, then its + value will not be prefilled, but the user will still be prompted for it (with an empty value). --> + <InputClaim ClaimTypeReferenceId="displayName" /> + <InputClaim ClaimTypeReferenceId="givenName" /> + <InputClaim ClaimTypeReferenceId="surname" /> + </InputClaims> + <!User will be asked to input or update these values--> + <DisplayClaims> + <DisplayClaim ClaimTypeReferenceId="displayName"/> + <DisplayClaim ClaimTypeReferenceId="givenName"/> + <DisplayClaim ClaimTypeReferenceId="surname"/> + </DisplayClaims> ++ <OutputClaims> + <!-- These claims are not shown to the user because their value is obtained through the "ValidationTechnicalProfiles" + referenced below, or a default value is assigned to the claim. A claim is only shown to the user to provide a + value if its value cannot be obtained through any other means. --> + <OutputClaim ClaimTypeReferenceId="objectId" /> + <OutputClaim ClaimTypeReferenceId="newUser" /> + <!<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />--> + + <!-- Optional claims. These claims are collected from the user and can be modified. If a claim is to be persisted in the directory after having been + collected from the user, it needs to be added as a PersistedClaim in the ValidationTechnicalProfile referenced below, i.e. + in AAD-UserWriteUsingAlternativeSecurityId. --> + <OutputClaim ClaimTypeReferenceId="displayName" /> + <OutputClaim ClaimTypeReferenceId="givenName" /> + <OutputClaim ClaimTypeReferenceId="surname" /> + </OutputClaims> + <ValidationTechnicalProfiles> + <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingAlternativeSecurityId" /> + </ValidationTechnicalProfiles> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + <!--</ClaimsProviders>--> +``` ++The claims provider we've added contains a self-asserted technical profile, *SelfAsserted-Social*. The self-asserted technical profile uses the *AAD-UserWriteUsingAlternativeSecurityId* Technical Profile as a validation technical profile. So, the *AAD-UserWriteUsingAlternativeSecurityId* Technical Profile executes when the user selects the **Continue** button (see screenshot in [step 7](#step-7test-policy)). ++Also, notice that we've added the content definition, *socialAccountsignupContentDefinition*, that we configured in [step 3.5](#step-35configure-content-definition) in the metadata section. ++## Step 4 - Update the User journey orchestration steps ++In the `ContosoCustomPolicy.XML` file, locate the `HelloWorldJourney` user journey and replace all the orchestration steps with the steps shown in the following code: ++```xml + <!--<OrchestrationSteps>--> + ... + <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp"> + <ClaimsProviderSelections> + <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" /> + </ClaimsProviderSelections> + </OrchestrationStep> + + <OrchestrationStep Order="2" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="FacebookExchange" + TechnicalProfileReferenceId="Facebook-OAUTH" /> + </ClaimsExchanges> + </OrchestrationStep> + + <!-- For social IDP authentication, attempt to find the user account in the + directory. --> + <OrchestrationStep Order="3" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId" /> + </ClaimsExchanges> + </OrchestrationStep> + + <!-- Show self-asserted page only if the directory does not have the user account + already (i.e. we don't have an objectId). --> + <OrchestrationStep Order="4" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" /> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="5" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" /> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> + <!--</OrchestrationSteps>--> +``` +In the orchestration, we've used make reference to technical profiles that enable a user to sign in by using a social account. ++When the custom policy runs: ++- **Orchestration Step 1** - This step includes a *ClaimsProviderSelections* element, which lists the available sign-in options a user can choose from. In this case, we've only have one option, *FacebookExchange*, so when the policy runs, users are taken directly to Facebook.com in step 2 as shown by the `TargetClaimsExchangeId` attribute. ++- **Orchestration Step 2** - The *Facebook-OAUTH* technical profile executes, so the user is redirected to Facebook to sign in. ++- **Orchestration Step 3** - In step 3, the *AAD-UserReadUsingAlternativeSecurityId* technical profile executes to try to read the user social account from Azure AD storage. If the social account is found, `objectId` is returned as an output claim. ++- **Orchestration Step 4** - This step runs if the user doesn't already exist (`objectId` doesn't exist). It shows the form that collects more information from the user or updates similar information obtained from the social account. ++- **Orchestration Step 5** - This step runs if the user doesn't already exist (`objectId` doesn't exist), so the *AAD-UserWriteUsingAlternativeSecurityId* Technical Profile executes to write the social account into Azure AD. ++- **Orchestration Step 6** - Finally, step 6 assembles and returns the JWT token at the end of the policyΓÇÖs execution. ++## Step 5 - Update relying party output claims ++In the `ContosoCustomPolicy.XML` file, locate the *RelyingParty* element, and then replace all the output claims collection with the following code: ++```xml + <OutputClaim ClaimTypeReferenceId="displayName" /> + <OutputClaim ClaimTypeReferenceId="givenName" /> + <OutputClaim ClaimTypeReferenceId="surname" /> + <OutputClaim ClaimTypeReferenceId="email" /> + <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/> + <OutputClaim ClaimTypeReferenceId="identityProvider" /> +``` +We've added the identity provider (*identityProvider*) as an output claim, so it will be included in the JWT token returned to the relying party application. + +## Step 6 - Upload policy ++Follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file) to upload your policy file. If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. ++## Step 7 - Test policy ++Follow the steps in [Test the custom policy](custom-policies-series-validate-user-input.md#step-6test-the-custom-policy) to test your custom policy. ++You're redirected to a Facebook sign-in page. Enter your Facebook credentials, and then select **Log In**. +You're directly redirected to Facebook as we set it so in our orchestration steps since we don't have multiple sign-in options to choose from. Typically, in an app, you'd add a button like **Sign in with Facebook**, which when selected, runs the policy. ++If it's the first time running this policy (social account doesn't already exist in Azure AD storage), you see a screenshot such as the one shown below. You won't see this screen in subsequent policy executions as the social account already exist in Azure AD storage. +++Enter or update **Display Name**, **Given Name** and the **Surname**, and then select **Continue** button. ++After the policy finishes execution, you're redirected to https://jwt.ms, and you see a decoded JWT token. It looks similar to the following JWT token snippet: ++```json +{ + "typ": "JWT", + "alg": "RS256", + "kid": "pxLOMWFgP4T..." +}.{ + ... + "acr": "b2c_1a_contosocustompolicy", + ... + "given_name": "Maurice", + "family_name": "Paulet", + "name": "Maurice Paulet", + "email": "maurice.p@contoso.com", + "idp": "facebook.com" +}.[Signature] +``` ++Notice the identity provider, `"idp": "facebook.com"`, has been included in the JWT token. ++## A combined local and social sign-in ++In this article, our user journey orchestration steps only reference technical profiles that enable a user to sign in by using a social account. We can modify the orchestration steps to enable a user to sign in by using either a local account or a social account. To do so, the first orchestration step's `ClaimsProviderSelections` element lists the sign-in options available to the user. ++Use the following steps to add a combined local and social account: ++1. In the `ContosoCustomPolicy.XML` file, locate the `AccountTypeInputCollector` self-asserted technical profile, and then add `authenticationSource` claim in its output claims collection by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localIdpAuthentication" AlwaysUseDefaultValue="true" /> + ``` ++1. In the `UserJourneys` section, add a new user journey, *LocalAndSocialSignInAndSignUp* by using the following code: ++ ```xml + <!--<UserJourneys>--> + ... + <UserJourney Id="LocalAndSocialSignInAndSignUp"> + <OrchestrationSteps> + <!--Orchestration steps will be added here--> + </OrchestrationSteps> + </UserJourney> + <!--</UserJourneys>--> + ``` ++1. In the user journey you've created, *LocalAndSocialSignInAndSignUp*, add orchestration steps by using the following code: + + ```xml + <!--<UserJourneys> + ... + <UserJourney Id="LocalAndSocialSignInAndSignUp"> + <OrchestrationSteps>--> + <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="SignupOrSigninContentDefinition"> + <ClaimsProviderSelections> + <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" /> + <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" /> + </ClaimsProviderSelections> + <ClaimsExchanges> + <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="UserSignInCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + <!-- Check if the user has selected to sign in using one of the social providers --> + <OrchestrationStep Order="2" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" /> + <ClaimsExchange Id="AccountTypeInputCollectorClaimsExchange" TechnicalProfileReferenceId="AccountTypeInputCollector"/> + </ClaimsExchanges> + </OrchestrationStep> ++ <!--For Local sign in option start--> ++ <OrchestrationStep Order="3" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>accountType</Value> + <Value>work</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>authenticationSource</Value> + <Value>socialIdpAuthentication</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="GetAccessCodeClaimsExchange" TechnicalProfileReferenceId="AccessCodeInputCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="4" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>authenticationSource</Value> + <Value>socialIdpAuthentication</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="UserInformationCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="5" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>authenticationSource</Value> + <Value>socialIdpAuthentication</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserReaderExchange" TechnicalProfileReferenceId="AAD-UserRead"/> + </ClaimsExchanges> + </OrchestrationStep> + <!--For Local sign in option end--> ++ <!--For social sign in option start--> + <!-- For social IDP authentication, attempt to find the user account in the + directory. --> + <OrchestrationStep Order="6" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>authenticationSource</Value> + <Value>localIdpAuthentication</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId" /> + </ClaimsExchanges> + </OrchestrationStep> + + <!-- Show self-asserted page only if the directory does not have the user account + already (i.e. we do not have an objectId). --> + <OrchestrationStep Order="7" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>authenticationSource</Value> + <Value>localIdpAuthentication</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" /> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="8" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>authenticationSource</Value> + <Value>localIdpAuthentication</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" /> + </ClaimsExchanges> + </OrchestrationStep> + <!--For social sign in option end--> + <OrchestrationStep Order="9" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="UserInputMessageClaimGenerator"/> + </ClaimsExchanges> + </OrchestrationStep> ++ <OrchestrationStep Order="10" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> + <!-- </OrchestrationSteps> + </UserJourney> + </UserJourneys>--> + ``` + + In the fist step, we specify the options a user needs to choose from in their journey, local or social authentication. In the steps that follow, we use preconditions to track the option the user picked or the stage of the journey at which the user is. For example, we use the `authenticationSource` claim to differentiate between a local authentication journey and a social authentication journey. + +1. In the `RelyingParty` section, change *DefaultUserJourney's* `ReferenceId` to `LocalAndSocialSignInAndSignUp` ++1. Use the procedure in [step 6](#step-6upload-policy) and [step 7](#step-7test-policy) to upload and run your policy. After you run the policy, you'll see a screen similar to the following screenshot. ++ :::image type="content" source="media/custom-policies-series-sign-up-or-sign-in-federation/screenshot-combined-local-and-social-sign-up-or-sign-in.png" alt-text="A screenshot of combined local and social sign-up or sign-in interface."::: ++ You can observe that a user can sign up or sign in by using either a local account or a social account. ++## Next steps ++- Learn more about how to [Define an OAuth2 technical profile in an Azure Active Directory B2C custom policy](oauth2-technical-profile.md). |
active-directory-b2c | Custom Policies Series Sign Up Or Sign In | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-sign-up-or-sign-in.md | + + Title: Set up a sign-up and sign-in flow for a local account by using Azure Active Directory B2C custom policy ++description: Learn how to configure a sign-up and sign-in flow for a local account, using email and password, by using Azure Active Directory B2C custom policy. ++++++++ Last updated : 01/30/2023+++++++# Set up a sign-up and sign-in flow for a local account by using Azure Active Directory B2C custom policy ++In [Create and read a user account by using Azure Active Directory B2C custom policy](custom-policies-series-store-user.md) article, a user creates a new user account but doesn't sign in to it. ++In this article, you learn how to write an Azure Active Directory B2C (Azure AD B2C) custom policy that allows a user to either create an Azure AD B2C local account or sign in into one. A local account refers to an account that is created in your Azure AD B2C tenant when a user signs up into your application. ++## Overview ++Azure AD B2C uses OpenID Connect authentication protocol to verify user credentials. In Azure AD B2C, you send the user credentials alongside other information to a secure endpoint, which then determines if the credentials are valid or not. In a nutshell, when you use Azure AD B2C's implementation of OpenID Connect, you can outsource sign-up, sign in, and other identity management experiences in your web applications to Azure Active Directory (Azure AD). ++Azure AD B2C custom policy provides a OpenID Connect technical profile, which you use to make a call to a secure Microsoft endpoint. Learn more about [OpenID Connect technical profile](openid-connect-technical-profile.md). ++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Create and read a user account by using Azure Active Directory B2C custom policy](custom-policies-series-store-user.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++++## Step 1 - Configure OpenID Connect technical profile ++To configure an OpenID Connect technical profile, you need to perform three steps: ++- Declare more claims. +- Register apps in your Azure portal. +- Finally, configure OpenID Connect Technical Profile itself ++### Step 1.1 - Declare more claims ++In the `ContosoCustomPolicy.XML` file, locate the *ClaimsSchema* section, and then add more claims by using the following code: ++```xml + <!--<ClaimsSchema>--> + ... + <ClaimType Id="grant_type"> + <DisplayName>grant_type</DisplayName> + <DataType>string</DataType> + <UserHelpText>Special parameter passed for local account authentication to login.microsoftonline.com.</UserHelpText> + </ClaimType> + + <ClaimType Id="scope"> + <DisplayName>scope</DisplayName> + <DataType>string</DataType> + <UserHelpText>Special parameter passed for local account authentication to login.microsoftonline.com.</UserHelpText> + </ClaimType> + + <ClaimType Id="nca"> + <DisplayName>nca</DisplayName> + <DataType>string</DataType> + <UserHelpText>Special parameter passed for local account authentication to login.microsoftonline.com.</UserHelpText> + </ClaimType> + + <ClaimType Id="client_id"> + <DisplayName>client_id</DisplayName> + <DataType>string</DataType> + <AdminHelpText>Special parameter passed to EvoSTS.</AdminHelpText> + <UserHelpText>Special parameter passed to EvoSTS.</UserHelpText> + </ClaimType> + + <ClaimType Id="resource_id"> + <DisplayName>resource_id</DisplayName> + <DataType>string</DataType> + <AdminHelpText>Special parameter passed to EvoSTS.</AdminHelpText> + <UserHelpText>Special parameter passed to EvoSTS.</UserHelpText> + </ClaimType> + <!--</ClaimsSchema>--> +``` ++### Step 1.2 - Register Identity Experience Framework applications ++Azure AD B2C requires you to register two applications that it uses to sign up and sign in users with local accounts: IdentityExperienceFramework, a web API, and ProxyIdentityExperienceFramework, a native app with delegated permission to the IdentityExperienceFramework app. ++If you haven't already done so, register the following applications. To automate the walk-through below, visit the [IEF Setup App](https://aka.ms/iefsetup) and follow the instructions: ++1. Use the steps in [Register the IdentityExperienceFramework application](tutorial-create-user-flows.md?pivots=b2c-custom-policy#register-the-identityexperienceframework-application) to register the Identity Experience Framework application. Copy the **Application (client) ID**, *appID*, for the Identity Experience Framework application registration for use on the next step. ++1. Use the steps in [Register the ProxyIdentityExperienceFramework application](tutorial-create-user-flows.md?pivots=b2c-custom-policy#register-the-proxyidentityexperienceframework-application) to register Proxy Identity Experience Framework application. Copy the **Application (client) ID**, *proxyAppID*, for the Proxy Identity Experience Framework application registration for use on the next step. ++### Step 1.3 - Configure OpenID Connect technical profile ++In the `ContosoCustomPolicy.XML` file, locate the *ClaimsProviders* section, and then add a Claims Provider element that holds your OpenID Connect Technical Profile by using the following code: ++```xml + <!--<ClaimsProviders>--> + ... + <ClaimsProvider> + <DisplayName>OpenID Connect Technical Profiles</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="SignInUser"> + <DisplayName>Sign in with Local Account</DisplayName> + <Protocol Name="OpenIdConnect" /> + <Metadata> + <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We didn't find this account</Item> + <Item Key="UserMessageIfInvalidPassword">Your password or username is incorrect</Item> + <Item Key="UserMessageIfOldPasswordUsed">You've used an old password.</Item> + <Item Key="ProviderName">https://sts.windows.net/</Item> + <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item> + <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item> + <Item Key="response_types">id_token</Item> + <Item Key="response_mode">query</Item> + <Item Key="scope">email openid</Item> + <!-- Policy Engine Clients --> + <Item Key="UsePolicyInRedirectUri">false</Item> + <Item Key="HttpBinding">POST</Item> + <Item Key="client_id">proxyAppID</Item> + <Item Key="IdTokenAudience">appID</Item> + </Metadata> + <InputClaims> + <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="username" Required="true" /> + <InputClaim ClaimTypeReferenceId="password" PartnerClaimType="password" Required="true" /> + <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" /> + <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" /> + <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" /> + <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="proxyAppID" /> + <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="appID" /> + </InputClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" /> + </OutputClaims> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> + <!--</ClaimsProviders>--> +``` ++Replace both instances of: ++- *appID* with **Application (client) ID** of the Identity Experience Framework application you copied in [step 1.2](#step-12register-identity-experience-framework-applications). ++- *proxyAppID* with **Application (client) ID** of the Proxy Identity Experience Framework application you copied in [step 1.2](#step-12register-identity-experience-framework-applications). ++## Step 2 - Configure the sign-in user interface ++When your policy runs, the user needs to see a user interface that allows them to sign in. The user interface also has an option to sign up if they don't already have an account. To do so, you need to perform two steps: ++- Configure a self-asserted technical profile, which displays the sign-in form to the user. +- Configure content definition for the sign-in user interface. ++### Step 2.1 - Configure a sign-in user interface technical profile ++In the `ContosoCustomPolicy.XML` file, locate the `SignInUser` technical profile and add a SelfAsserted Technical Profile after it by using the following code: +++```xml + <TechnicalProfile Id="UserSignInCollector"> + <DisplayName>Local Account Signin</DisplayName> + <Protocol Name="Proprietary" + Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="setting.operatingMode">Email</Item> + <Item Key="SignUpTarget">AccountTypeInputCollectorClaimsExchange</Item> + </Metadata> + <DisplayClaims> + <OutputClaim ClaimTypeReferenceId="email" Required="true" /> + <OutputClaim ClaimTypeReferenceId="password" Required="true" /> + </DisplayClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="email" /> + <OutputClaim ClaimTypeReferenceId="password" /> + <OutputClaim ClaimTypeReferenceId="objectId" /> + </OutputClaims> + <ValidationTechnicalProfiles> + <ValidationTechnicalProfile ReferenceId="SignInUser" /> + </ValidationTechnicalProfiles> + </TechnicalProfile> +``` ++We've added a SelfAsserted Technical Profile, *UserSignInCollector*, which displays the sign-in form to the user. We've configured the technical profile to collect the userΓÇÖs email address as their sign-in name as indicated in the `setting.operatingMode` metadata. The sign-in form includes a sign-up link, which leads the user to a sign-up form as indicated by the `SignUpTarget` metadata. You'll see how we set up the *SignUpWithLogonEmailExchange* `ClaimsExchange` in the orchestration steps. ++Also, we've added the *SignInUser* OpenID Connect Technical Profile as a *ValidationTechnicalProfile*. So, the *SignInUser* technical profile executes when the user selects the **Sign in** button (see screenshot in [step 5](#step-5test-policy)). ++In the next step ([step 2.2](#step-22configure-sign-in-interface-content-definition)), we configure a content definition that we'll use in this SelfAsserted Technical Profile. ++### Step 2.2 - Configure sign-in interface content definition ++In the `ContosoCustomPolicy.XML` file, locate the *ContentDefinitions* section, and then sign-in [Content Definition](contentdefinitions.md) by using the following code: ++```xml + <!--<ContentDefinitions>--> + ... + <ContentDefinition Id="SignupOrSigninContentDefinition"> + <LoadUri>~/tenant/templates/AzureBlue/unified.cshtml</LoadUri> + <RecoveryUri>~/common/default_page_error.html</RecoveryUri> + <DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.7</DataUri> + <Metadata> + <Item Key="DisplayName">Signin and Signup</Item> + </Metadata> + </ContentDefinition> + <!--</ContentDefinitions>--> +``` +We've configured a content definition for our self-asserted technical profile, `SignupOrSigninContentDefinition`. We can specify it in the technical profile using the metadata element or specify it when we reference the technical profile in the orchestration steps. Previously, we learned how to specify a content definition directly in the self-asserted technical profile, so in this article, we'll learn how to specify it when we reference the technical profile in the orchestration steps, [step 3](#step-3update-the-user-journey-orchestration-steps). +++## Step 3 - Update the User journey orchestration steps ++In the `ContosoCustomPolicy.XML` file, locate the *HelloWorldJourney* user journey and replace all its orchestration steps collection with the following code: ++```xml + <!--<OrchestrationSteps>--> + ... + <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="SignupOrSigninContentDefinition"> + <ClaimsProviderSelections> + <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" /> + </ClaimsProviderSelections> + <ClaimsExchanges> + <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="UserSignInCollector" /> + </ClaimsExchanges> + </OrchestrationStep> ++ <OrchestrationStep Order="2" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="AccountTypeInputCollectorClaimsExchange" TechnicalProfileReferenceId="AccountTypeInputCollector"/> + </ClaimsExchanges> + </OrchestrationStep> ++ <OrchestrationStep Order="3" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> + <Value>accountType</Value> + <Value>company</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="GetAccessCodeClaimsExchange" TechnicalProfileReferenceId="AccessCodeInputCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="4" Type="ClaimsExchange"> + <Preconditions> + <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> + <Value>objectId</Value> + <Action>SkipThisOrchestrationStep</Action> + </Precondition> + </Preconditions> + <ClaimsExchanges> + <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="UserInformationCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="5" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserReaderExchange" TechnicalProfileReferenceId="AAD-UserRead"/> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="6" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="UserInputMessageClaimGenerator"/> + </ClaimsExchanges> + </OrchestrationStep> + + <OrchestrationStep Order="7" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> + <!--</OrchestrationSteps>--> +``` ++In orchestration steps two to five, we've used preconditions to determine if Orchestration Step should run. We need to determine if the user is signing in or signing up. ++When the custom policy runs: ++- **Orchestration Step 1** - Displays sign-in page, so the user can sign in or select the **Sign up now** link. Notice that we specify the content definition that the *UserSignInCollector* self-asserted technical profile uses to display the sign-in form. + +- **Orchestration Step 2** - This step runs if the user signs up (`objectId` doesn't exist), so we display the account type selection form by invoking the *AccountTypeInputCollector* self-asserted technical profile. ++- **Orchestration Step 3** - This step runs if the user signs up (`objectId` doesn't exist), and that a user doesn't select a company `accountType`. So we've to ask the user to input an `accessCode` by invoking the *AccessCodeInputCollector* self-asserted technical profile. ++- **Orchestration Step 4** - This step runs if the user signs up (objectId doesn't exist), so we display the sign-up form by invoking the +*UserInformationCollector* self-asserted technical profile. This step runs whether a user signs up or signs in. ++- **Orchestration Step 5** - This step reads account information from Azure AD (we invoke *AAD-UserRead* Azure AD technical profile), so it runs whether a user signs up or signs in. ++- **Orchestration Step 6** - This step invokes the *UserInputMessageClaimGenerator* technical profile to assemble the userΓÇÖs greeting message. ++- **Orchestration Step 7** - Finally, step 8 assembles and returns the JWT token at the end of the policyΓÇÖs execution. ++## Step 4 - Upload policy ++Follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file) to upload your policy file. If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. ++## Step 5 - Test policy ++Follow the steps in [Test the custom policy](custom-policies-series-validate-user-input.md#step-6test-the-custom-policy) to test your custom policy. Once the policy runs, you'll see an interface similar to the screenshot below: +++You can sign in by entering the **Email Address** and **Password** of an existing account. If you don't already have an account, you need to select the **Sign up now** link to create a new user account. ++## Next steps ++- Learn how to [Set up a sign-up and sign-in flow with a social account by using Azure Active Directory B2C custom policy](custom-policies-series-sign-up-or-sign-in-federation.md). ++- Learn how to [Remove the sign-up link](add-sign-in-policy.md), so users can just sign in. ++- Learn more about [OpenID Connect technical profile](openid-connect-technical-profile.md). |
active-directory-b2c | Custom Policies Series Store User | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-store-user.md | + + Title: Create a user account by using Azure Active Directory B2C custom policy ++description: Learn how to create a user account in Azure AD B2C storage by using a custom policy. ++++++++ Last updated : 01/30/2023++++++# Create and read a user account by using Azure Active Directory B2C custom policy ++Azure Active Directory B2C (Azure AD B2C) is built on Azure Active Directory (Azure AD), and so it uses Azure AD storage to store user accounts. Azure AD B2C directory user profile comes with a built-in set of attributes, such as given name, surname, city, postal code, and phone number, but you can [extend the user profile with your own custom attributes](user-flow-custom-attributes.md) without requiring an external data store. ++Your custom policy can connect to Azure AD storage by using [Azure AD technical profile](active-directory-technical-profile.md) to store, update or delete user information. In this article, you'll learn how to configure a set of Azure AD technical profiles to store and read a user account before a JWT token is returned. ++## Scenario overview ++In [Call a REST API by using Azure Active Directory B2C custom policy](custom-policies-series-call-rest-api.md) article, we collected information from the user, validated the data, called a REST API, and finally returned a JWT without storing a user account. We must store the user information so that we don't lose the information once the policy finishes execution. This time, once we collect the user information and validate it, we need to store the user information in Azure AD B2C storage, and then read before we return the JWT token. The complete process is shown in the following diagram. +++++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Call a REST API by using Azure Active Directory B2C custom policy](custom-policies-series-call-rest-api.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++## Step 1 - Declare claims ++You need to declare two more claims, `userPrincipalName`, and `passwordPolicies`: + +1. In the `ContosoCustomPolicy.XML` file, locate the *ClaimsSchema* element and declare `userPrincipalName` and `passwordPolicies` claims by using the following code: ++ ```xml + <ClaimType Id="userPrincipalName"> + <DisplayName>UserPrincipalName</DisplayName> + <DataType>string</DataType> + <UserHelpText>Your user name as stored in the Azure Active Directory.</UserHelpText> + </ClaimType> + <ClaimType Id="passwordPolicies"> + <DisplayName>Password Policies</DisplayName> + <DataType>string</DataType> + <UserHelpText>Password policies used by Azure AD to determine password strength, expiry etc.</UserHelpText> + </ClaimType> + ``` + + Learn more about the uses of the `userPrincipalName` and `passwordPolicies` claims in [User profile attributes](user-profile-attributes.md) article. ++## Step 2 - Create Azure AD technical profiles ++You need to configure two [Azure AD Technical Profile](active-directory-technical-profile.md). One technical profile writes user details into Azure AD storage, and the other reads a user account from Azure AD storage. ++1. In the `ContosoCustomPolicy.XML` file, locate the *ClaimsProviders* element, and add a new claims provider by using the code below. This claims provider holds the Azure AD technical profiles: ++ ```xml + <ClaimsProvider> + <DisplayName>Azure AD Technical Profiles</DisplayName> + <TechnicalProfiles> + <!--You'll add you Azure AD Technical Profiles here--> + </TechnicalProfiles> + </ClaimsProvider> + ``` +1. In the claims provider you just created, add an Azure AD technical profile by using the following code: ++ ```xml + <TechnicalProfile Id="AAD-UserWrite"> + <DisplayName>Write user information to AAD</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="Operation">Write</Item> + <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item> + <Item Key="UserMessageIfClaimsPrincipalAlreadyExists">The account already exists. Try to create another account</Item> + </Metadata> + <InputClaims> + <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" /> + </InputClaims> + <PersistedClaims> + <PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" /> + <PersistedClaim ClaimTypeReferenceId="displayName" /> + <PersistedClaim ClaimTypeReferenceId="givenName" /> + <PersistedClaim ClaimTypeReferenceId="surname" /> + <PersistedClaim ClaimTypeReferenceId="password"/> + <PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration,DisableStrongPassword" /> + </PersistedClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" /> + <OutputClaim ClaimTypeReferenceId="userPrincipalName" /> + <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" /> + </OutputClaims> + </TechnicalProfile> + ``` ++ We've added a new Azure AD technical profile, *AAD-UserWrite*. You need to take note of the following important parts of the technical profile: + + - *Operation*: The operation specifies the action to be performed, in this case, *Write*. Learn more about other [operations in an Azure AD technical provider](active-directory-technical-profile.md#azure-ad-technical-profile-operations). + + - *Persisted claims*: The *PersistedClaims* element contains all of the values that should be stored into Azure AD storage. + + - *InputClaims*: The *InputClaims* element contains a claim, which is used to look up an account in the directory, or create a new one. There must be exactly one input claim element in the input claims collection for all Azure AD technical profiles. This technical profile uses the *email* claim, as the key identifier for the user account. Learn more about [other key identifiers you can use uniquely identify a user account](active-directory-technical-profile.md#inputclaims). + ++1. In the `ContosoCustomPolicy.XML` file, locate the `AAD-UserWrite` technical profile, and then add a new technical profile after it by using the following code: ++ ```xml + <TechnicalProfile Id="AAD-UserRead"> + <DisplayName>Read user from Azure AD storage</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="Operation">Read</Item> + <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item> + <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item> + </Metadata> + <InputClaims> + <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" /> + </InputClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="objectId" /> + <OutputClaim ClaimTypeReferenceId="userPrincipalName" /> + <OutputClaim ClaimTypeReferenceId="givenName"/> + <OutputClaim ClaimTypeReferenceId="surname"/> + <OutputClaim ClaimTypeReferenceId="displayName"/> + </OutputClaims> + </TechnicalProfile> + ``` ++ We've added a new Azure AD technical profile, `AAD-UserRead`. We've configured this technical profile to perform a read operation, and to return `objectId`, `userPrincipalName`, `givenName`, `surname` and `displayName` claims if a user account with the `email` in the `InputClaim` section is found. ++## Step 3 - Use the Azure AD technical profile ++After we collect user details by using the `UserInformationCollector` self-asserted technical profile, we need to write a user account into Azure AD storage by using the `AAD-UserWrite` technical profile. To do so, use the `AAD-UserWrite` technical profile as a validation technical profile in the `UserInformationCollector` self-asserted technical profile. ++In the `ContosoCustomPolicy.XML` file, locate the `UserInformationCollector` technical profile, and then add `AAD-UserWrite` technical profile as a validation technical profile in the `ValidationTechnicalProfiles` collection. You need to add this after the `CheckCompanyDomain` validation technical profile. ++We'll use the `AAD-UserRead` technical profile in the user journey orchestration steps to read the user details before issuing a JWT token. ++## Step 4 - Update the ClaimGenerator technical profile ++We use the `ClaimGenerator` technical profile to execute three claims transformations, *GenerateRandomObjectIdTransformation*, *CreateDisplayNameTransformation* and *CreateMessageTransformation*. ++1. In the `ContosoCustomPolicy.XML` file, locate the `ClaimGenerator` technical profile and replace it with the following code: ++ ```xml + <TechnicalProfile Id="UserInputMessageClaimGenerator"> + <DisplayName>User Message Claim Generator Technical Profile</DisplayName> + <Protocol Name="Proprietary" + Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="message" /> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="CreateMessageTransformation" /> + </OutputClaimsTransformations> + </TechnicalProfile> + + <TechnicalProfile Id="UserInputDisplayNameGenerator"> + <DisplayName>Display Name Claim Generator Technical Profile</DisplayName> + <Protocol Name="Proprietary" + Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="displayName" /> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="CreateDisplayNameTransformation" /> + </OutputClaimsTransformations> + </TechnicalProfile> + ``` + We've broken the technical profile into two separate technical profiles. The *UserInputMessageClaimGenerator* technical profile generates the message sent as claim in the JWT token. The *UserInputDisplayNameGenerator* technical profile generates the `displayName` claim. The `displayName` claim value must be available before the `AAD-UserWrite` technical profile writes the user record into Azure AD storage. In the new code, we remove the *GenerateRandomObjectIdTransformation* as the `objectId` is created and returned by Azure AD after an account is created, so we don't need to generate it ourselves within the policy. ++1. In the `ContosoCustomPolicy.XML` file, locate the `UserInformationCollector` self-asserted technical profile, and then add the `UserInputDisplayNameGenerator` technical profile as a validation technical profile. After you do so, the `UserInformationCollector` technical profile's `ValidationTechnicalProfiles` collection should look similar to the following code: +++ ```xml + <!--<TechnicalProfile Id="UserInformationCollector">--> + <ValidationTechnicalProfiles> + <ValidationTechnicalProfile ReferenceId="CheckCompanyDomain"> + <Preconditions> + <Precondition Type="ClaimEquals" ExecuteActionsIf="false"> + <Value>accountType</Value> + <Value>work</Value> + <Action>SkipThisValidationTechnicalProfile</Action> + </Precondition> + </Preconditions> + </ValidationTechnicalProfile> + <ValidationTechnicalProfile ReferenceId="DisplayNameClaimGenerator"/> + <ValidationTechnicalProfile ReferenceId="AAD-UserWrite"/> + </ValidationTechnicalProfiles> + <!--</TechnicalProfile>--> + ``` ++ You must add the validation technical profile before `AAD-UserWrite` as the `displayName` claim value must be available before the `AAD-UserWrite` technical profile writes the user record into Azure AD storage. ++## Step 5 - Update the user journey orchestration steps ++Locate your `HelloWorldJourney` user journey and replace all the orchestration steps with the following code: ++```xml + <!--<OrchestrationSteps>--> + <OrchestrationStep Order="1" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="AccountTypeInputCollectorClaimsExchange" TechnicalProfileReferenceId="AccountTypeInputCollector"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="2" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetAccessCodeClaimsExchange" TechnicalProfileReferenceId="AccessCodeInputCollector" /> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="3" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="4" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="AADUserReaderExchange" TechnicalProfileReferenceId="AAD-UserRead"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="5" Type="ClaimsExchange"> + <ClaimsExchanges> + <ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="UserInputMessageClaimGenerator"/> + </ClaimsExchanges> + </OrchestrationStep> + <OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/> + <!--</OrchestrationSteps>--> +``` ++In orchestration step `4`, we execute the `AAD-UserRead` technical profile to read the user details (to be included in the JWT token) from the created user account. ++Since we don't store the `message` claim, in orchestration step `5`, we execute the `UserInputMessageClaimGenerator` to generate the `message` claim for inclusion on the JWT token. + +## Step 6 - Upload policy ++Follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file) to upload your policy file. If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. ++## Step 7 - Test policy ++Follow the steps in [Test the custom policy](custom-policies-series-validate-user-input.md#step-6test-the-custom-policy) to test your custom policy. ++After the policy finishes execution, and you receive your ID token, check that the user record has been created: ++1. Sign in to the [Azure portal](https://portal.azure.com/) with Global Administrator or Privileged Role Administrator permissions. ++1. Make sure you're using the directory that contains your Azure AD B2C tenant: + + 1. Select the **Directories + subscriptions** icon in the portal toolbar. ++ 1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the Directory name list, and then select Switch. ++1. Under **Azure services**, select **Azure AD B2C**. Or use the search box to find and select **Azure AD B2C**. ++1. Under **Manage**, select **Users**. ++1. Locate the user account that you just created, and select it. The account profile looks similar to the screenshot below: ++ :::image type="content" source="media/custom-policies-series-store-user/screenshot-of-create-users-custom-policy.png" alt-text="A screenshot of creating a user account in Azure AD."::: +++In our *AAD-UserWrite* Azure AD Technical Profile, we specify that if the user already exists, we raise an error message. ++Test your custom policy again by using the same **Email Address**. Instead of the policy executing to completion to issue an ID token, you should see an error message similar to the screenshot below. +++> [!NOTE] +> The *password* claim value is a very important piece of information, so be very careful how you handle it in your custom policy. For a similar reason, Azure AD B2C treats the password claim value as a special value. When you collect the password claim value in the self-asserted technical profile, that value is only available within the same technical profile or within a validation technical profiles that are referenced by that same self-asserted technical profile. Once execution of that self-asserted technical profile completes, and moves to another technical profile, the value is lost. ++## Verify user email address ++We recommend that you verify a user's email before you use it to create a user account. When you verify email addresses, you make sure the accounts are created by real users. You also help users to be sure that they're using their correct email addresses to create an account. ++Azure AD B2C's custom policy provides a way to verify email address using [verification display control](display-control-verification.md). You send a verification code to the email. After the code has been sent, the user reads the message, enters the verification code into the control provided by the display control, and selects **Verify Code** button. ++A display control is a user interface element that has special functionality and interacts with the Azure Active Directory B2C (Azure AD B2C) back-end service. It allows the user to perform actions on the page that invoke a validation technical profile at the back end. Display controls are displayed on the page and are referenced by a self-asserted technical profile. ++To add email verification by using a display control, use the following steps: ++### Declare claim ++You need to declare a claim to be used to hold the verifications code. ++To declare the claim, in the `ContosoCustomPolicy.XML` file, locate the `ClaimsSchema` element and declare `verificationCode` claim by using the following code: ++```xml + <!--<ClaimsSchema>--> + ... + <ClaimType Id="verificationCode"> + <DisplayName>Verification Code</DisplayName> + <DataType>string</DataType> + <UserHelpText>Enter your verification code</UserHelpText> + <UserInputType>TextBox</UserInputType> + </ClaimType> + <!--</ClaimsSchema>--> +``` ++### Configure a send and verify code technical profile ++Azure AD B2C uses [Azure AD SSPR technical profile](aad-sspr-technical-profile.md) to verify an email address. This technical profile can generate and send a code to an email address or verifies the code depending on how you configure it. ++In the `ContosoCustomPolicy.XML` file, locate the `ClaimsProviders` element and add the claims provider by using the following code: ++```xml + <ClaimsProvider> + <DisplayName>Azure AD self-service password reset (SSPR)</DisplayName> + <TechnicalProfiles> + <TechnicalProfile Id="AadSspr-SendCode"> + <DisplayName>Send Code</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AadSsprProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="Operation">SendCode</Item> + </Metadata> + <InputClaims> + <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" /> + </InputClaims> + </TechnicalProfile> + <TechnicalProfile Id="AadSspr-VerifyCode"> + <DisplayName>Verify Code</DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AadSsprProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + <Metadata> + <Item Key="Operation">VerifyCode</Item> + </Metadata> + <InputClaims> + <InputClaim ClaimTypeReferenceId="verificationCode" /> + <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="emailAddress" /> + </InputClaims> + </TechnicalProfile> + </TechnicalProfiles> + </ClaimsProvider> +``` ++We've configured two technical profiles `AadSspr-SendCode` and `AadSspr-VerifyCode`. `AadSspr-SendCode` generates and sends a code to the email address specified in the `InputClaims` section whereas `AadSspr-VerifyCode` verifies the code. You specify the action you want to perform in the technical profile's metadata. ++### Configure a display control ++You need to configure an email verification display control to be able to verify users email. The email verification display control you configure will replace the email display claim that you use to collect an email from the user. ++To configure a display control, use the following steps: ++1. In the `ContosoCustomPolicy.XML` file, locate the `BuildingBlocks` section, and then add a display control as a child element by using the following code: ++ ```xml + <!--<BuildingBlocks>--> + .... + <DisplayControls> + <DisplayControl Id="emailVerificationControl" UserInterfaceControlType="VerificationControl"> + <DisplayClaims> + <DisplayClaim ClaimTypeReferenceId="email" Required="true" /> + <DisplayClaim ClaimTypeReferenceId="verificationCode" ControlClaimType="VerificationCode" Required="true" /> + </DisplayClaims> + <OutputClaims></OutputClaims> + <Actions> + <Action Id="SendCode"> + <ValidationClaimsExchange> + <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AadSspr-SendCode" /> + </ValidationClaimsExchange> + </Action> + <Action Id="VerifyCode"> + <ValidationClaimsExchange> + <ValidationClaimsExchangeTechnicalProfile TechnicalProfileReferenceId="AadSspr-VerifyCode" /> + </ValidationClaimsExchange> + </Action> + </Actions> + </DisplayControl> + </DisplayControls> + <!--</BuildingBlocks>--> + ``` ++ We've declared a display control, `emailVerificationControl`. Take note of the following important parts: ++ - *DisplayClaims* - Just like in a self-asserted technical profile, this section specifies a collection of claims to be collected from the user within the display control. + + - *Actions* - Specifies the order of actions to be performed by the display control. Each action references a technical profile that responsible to perform the actions. For example, the *SendCode* references the `AadSspr-SendCode` technical profile, which generates and sends a code to an email address. ++1. In the `ContosoCustomPolicy.XML` file, locate the `UserInformationCollector` self-asserted technical profile and replace the *email* display claim to `emailVerificationControl` display control: + + From: + + ```xml + <DisplayClaim ClaimTypeReferenceId="email" Required="true"/> + ``` ++ To: ++ ```xml + <DisplayClaim DisplayControlReferenceId="emailVerificationControl" /> + ``` ++1. Use the procedure in [step 6](#step-6upload-policy) and [step 7](#step-7test-policy) to upload your policy file, and test it. This time, you must verify your email address before a user account is created. ++## Update user account by using Azure AD technical profile ++You can configure an Azure AD technical profile to update a user account instead of attempting to create a new one. To do so, set the Azure AD technical profile to throw an error if the specified user account doesn't already exist in the `Metadata` collection by using the following code. The *Operation* needs to be set to *Write*: ++```xml + <!--<Item Key="Operation">Write</Item>--> + <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item> +``` ++## Use custom attributes ++In this article, you've learned how to store user details using [built-in user profile attributes](user-profile-attributes.md). However, you often need to create your own custom attributes to manage your specific scenario. To do so, follow the instructions in [Define custom attributes in Azure Active Directory B2C](user-flow-custom-attributes.md) article. ++## Next steps ++- Learn how to [Set up a sign-up and sign-in flow for a local account by using Azure Active Directory B2C custom policy](custom-policies-series-sign-up-or-sign-in.md). ++- Learn how to [define custom attributes in your custom policy](user-flow-custom-attributes.md?pivots=b2c-custom-policy). + +- Learn how to [add password expiration to custom policy](https://github.com/azure-ad-b2c/samples/tree/master/policies/force-password-reset-after-90-days). ++- Learn more about [Azure AD Technical Profile](active-directory-technical-profile.md). |
active-directory-b2c | Custom Policies Series Validate User Input | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/custom-policies-series-validate-user-input.md | + + Title: Validate user inputs by using Azure AD B2C custom policy ++description: Learn how to validate user inputs by using Azure Active Directory B2C custom policy. Learn how to validate user input by limiting user input options. Learn how to validate user input by using Predicates. Learn how to validate user input by using Regular Expressions. Learn how to validate user input by using validation technical profiles ++++++++ Last updated : 01/30/2023++++++# Validate user inputs by using Azure Active Directory B2C custom policy ++Azure Active Directory B2C (Azure AD B2C) custom policy not only allows you to make user inputs mandatory but also to validate them. You can mark user inputs as *required*, such as `<DisplayClaim ClaimTypeReferenceId="givenName" Required="true"/>`, but it doesn't mean your users will enter valid data. Azure AD B2C provides various ways to validate a user input. In this article, you'll learn how to write a custom policy that collects the user inputs and validates them by using the following approaches: ++- Restrict the data a user enters by providing a list of options to pick from. This approach uses *Enumerated Values*, which you add when you declare a claim. + +- Define a pattern that a user input must match. This approach uses *Regular Expressions*, which you add when you declare a claim. ++- Define a set of rules and require that a user input obeys one or more of the rules. This approach uses *Predicates*, which you add when you declare a claim. ++- Use the special claim type *reenterPassword* to validate that the user correctly re-entered their password during user input collection. ++- Configure a *Validation Technical Profile* that defines complex business rules that aren't possible to define at claim declaration level. For example, you collect a user input, which needs to be validated against a set of other values in another claim. +++## Prerequisites ++- If you don't have one already, [create an Azure AD B2C tenant](tutorial-create-tenant.md) that is linked to your Azure subscription. ++- [Register a web application](tutorial-register-applications.md), and [enable ID token implicit grant](tutorial-register-applications.md#enable-id-token-implicit-grant). For the Redirect URI, use https://jwt.ms. ++- You must have [Visual Studio Code (VS Code)](https://code.visualstudio.com/) installed in your computer. ++- Complete the steps in [Collect and manipulate user inputs by using Azure AD B2C custom policy](custom-policies-series-collect-user-input.md). This article is a part of [Create and run your own custom policies how-to guide series](custom-policies-series-overview.md). +++## Step 1 - Validate user input by limiting user input options ++If you know all the possible values that a user can enter for a given input, you can provide a finite set of values that a user must select from. You can use *DropdownSinglSelect*, *CheckboxMultiSelect*, and *RadioSingleSelect* [UserInputType](claimsschema.md#userinputtype) for this purpose. In this article, you'll use a *RadioSingleSelect* input type: ++1. In VS Code, open the file `ContosoCustomPolicy.XML`. ++1. In the `ClaimsSchema` element of the `ContosoCustomPolicy.XML` file, declare the following Claim Type: + + ```xml + <ClaimType Id="accountType"> + <DisplayName>Account Type</DisplayName> + <DataType>string</DataType> + <UserHelpText>The type of account used by the user</UserHelpText> + <UserInputType>RadioSingleSelect</UserInputType> + <Restriction> + <Enumeration Text="Contoso Employee Account" Value="work" SelectByDefault="true"/> + <Enumeration Text="Personal Account" Value="personal" SelectByDefault="false"/> + </Restriction> + </ClaimType> + ``` ++ We've declared *accountType* claim. When the claim's value is collected from the user, the user must select either *Contoso Employee Account* for a value *work* or *Personal Account* for a value *personal*. ++ Azure AD B2C also allows you to accommodate your policy to different languages and provides the account type restrictions for multiple languages. For more information, check out the [Localize the UI](configure-user-input.md#optional-localize-the-ui) of the [Add user attributes article](configure-user-input.md). ++1. Locate the technical profile with `Id="UserInformationCollector"`, add the *accountType* claim as display claim by using the following code: ++ ```xml + <DisplayClaim ClaimTypeReferenceId="accountType" Required="true"/> + ``` +1. In the technical profile with `Id="UserInformationCollector"`, add the *accountType* claim as an output claim by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="accountType"/> + ``` ++1. To include the account type claim in the access token, locate the `RelyingParty` element, add the *accountType* claim as a token claim by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="accountType" /> + ``` ++## Step 2 - Validate user input by using regular expressions ++When it's not possible to know all possible user input values in advance, you allow the user to input the data themselves. In this case, you can use *regular expressions (regex)* or [pattern](claimsschema.md#pattern) to dictate how a user input need to be formatted. For instance, an email must have the *at (@)* symbol and a *period (.)* somewhere in its text. ++When you declare a claim, custom policy allows you to define a regex, which the user input must match. You can optionally provide a message, which is shown to the user, if their input doesn't match the expression. ++1. Locate the `ClaimsSchema` element, and declare the *email* claim by using the following code: ++ ```xml + <ClaimType Id="email"> + <DisplayName>Email Address</DisplayName> + <DataType>string</DataType> + <DefaultPartnerClaimTypes> + <Protocol Name="OpenIdConnect" PartnerClaimType="email"/> + </DefaultPartnerClaimTypes> + <UserHelpText>Your email address. </UserHelpText> + <UserInputType>TextBox</UserInputType> + <Restriction> + <Pattern RegularExpression="^[a-zA-Z0-9.!#$%&'^_`{}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" HelpText="Please enter a valid email address something like maurice@contoso.com"/> + </Restriction> + </ClaimType> + ``` ++1. Locate the technical profile with `Id="UserInformationCollector"`, add the *email* claim as display claim by using the following code: ++ ```xml + <DisplayClaim ClaimTypeReferenceId="email" Required="true"/> + ``` ++1. In the technical profile with `Id="UserInformationCollector"`, add the *email* claim as an output claim by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="email"/> + ``` ++1. Locate the `RelyingParty` element, add the *email* as a token claim by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="email" /> + ``` ++## Step 3 - Validate user input by using predicates ++You've used regex to validate user inputs. However, regex have one weakness, that's, the error message displays until you correct input without showing you the specific requirement the input is missing. ++Predicates validations allow you to address this problem by allowing you to define a set of rules (predicates) and independent error message for each rule. In custom policies, a predicate has an inbuilt method, which defines the checks that you want to make. For example, you can use [IsLengthRange](predicates.md#islengthrange) predicate method to check whether a user *password* is within the range of minimum and maximum parameters (values) specified. ++While the *Predicates* define the validation to check against a claim type, the *PredicateValidations* groups a set of predicates to form a user input validation that can be applied to a claim type. For example, you create a predicate group of validation that validates different types of allowed characters for a password. Both *Predicates* and *PredicateValidations* elements are child elements of `BuildingBlocks` section of your policy file. +++1. Locate the `ClaimsSchema` element, and declare the *password* claim by using the following code: ++ ```xml + <ClaimType Id="password"> + <DisplayName>Password</DisplayName> + <DataType>string</DataType> + <AdminHelpText>Enter password</AdminHelpText> + <UserHelpText>Enter password</UserHelpText> + <UserInputType>Password</UserInputType> + </ClaimType> + ``` ++1. Add a `Predicates` element as a child of `BuildingBlocks` section by using the following code: ++ ```xml + <Predicates> + + </Predicates> + ``` ++1. Inside the `Predicates` element, define predicates by using the following code: ++ ```xml + <Predicate Id="IsLengthBetween8And64" Method="IsLengthRange" HelpText="The password must be between 8 and 64 characters."> + <Parameters> + <Parameter Id="Minimum">8</Parameter> + <Parameter Id="Maximum">64</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="Lowercase" Method="IncludesCharacters" HelpText="a lowercase letter"> + <Parameters> + <Parameter Id="CharacterSet">a-z</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="Uppercase" Method="IncludesCharacters" HelpText="an uppercase letter"> + <Parameters> + <Parameter Id="CharacterSet">A-Z</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="Number" Method="IncludesCharacters" HelpText="a digit"> + <Parameters> + <Parameter Id="CharacterSet">0-9</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="Symbol" Method="IncludesCharacters" HelpText="a symbol"> + <Parameters> + <Parameter Id="CharacterSet">@#$%^&*\-_+=[]{}|\\:',.?/`~"();!</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="PIN" Method="MatchesRegex" HelpText="The password must be numbers only."> + <Parameters> + <Parameter Id="RegularExpression">^[0-9]+$</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="AllowedAADCharacters" Method="MatchesRegex" HelpText="An invalid character was provided."> + <Parameters> + <Parameter Id="RegularExpression">(^([0-9A-Za-z\d@#$%^&*\-_+=[\]{}|\\:',?/`~"();! ]|(\.(?!@)))+$)|(^$)</Parameter> + </Parameters> + </Predicate> + + <Predicate Id="DisallowedWhitespace" Method="MatchesRegex" HelpText="The password must not begin or end with a whitespace character."> + <Parameters> + <Parameter Id="RegularExpression">(^\S.*\S$)|(^\S+$)|(^$)</Parameter> + </Parameters> + </Predicate> + ``` ++ We've defined several rules, which when put together described an acceptable password. Next, you can group predicates, to form a set of password policies that you can use in your policy. ++1. Add a `PredicateValidations` element as a child of `BuildingBlocks` section by using the following code: ++ ```xml + <PredicateValidations> + + </PredicateValidations> + ``` +1. Inside the `PredicateValidations` element, define PredicateValidations by using the following code: ++ ```xml + <PredicateValidation Id="SimplePassword"> + <PredicateGroups> + <PredicateGroup Id="DisallowedWhitespaceGroup"> + <PredicateReferences> + <PredicateReference Id="DisallowedWhitespace"/> + </PredicateReferences> + </PredicateGroup> + <PredicateGroup Id="AllowedCharactersGroup"> + <PredicateReferences> + <PredicateReference Id="AllowedCharacters"/> + </PredicateReferences> + </PredicateGroup> + <PredicateGroup Id="LengthGroup"> + <PredicateReferences> + <PredicateReference Id="IsLengthBetween8And64"/> + </PredicateReferences> + </PredicateGroup> + </PredicateGroups> + </PredicateValidation> + <PredicateValidation Id="StrongPassword"> + <PredicateGroups> + <PredicateGroup Id="DisallowedWhitespaceGroup"> + <PredicateReferences> + <PredicateReference Id="DisallowedWhitespace"/> + </PredicateReferences> + </PredicateGroup> + <PredicateGroup Id="AllowedCharactersGroup"> + <PredicateReferences> + <PredicateReference Id="AllowedCharacters"/> + </PredicateReferences> + </PredicateGroup> + <PredicateGroup Id="LengthGroup"> + <PredicateReferences> + <PredicateReference Id="IsLengthBetween8And64"/> + </PredicateReferences> + </PredicateGroup> + <PredicateGroup Id="CharacterClasses"> + <UserHelpText>The password must have at least 3 of the following:</UserHelpText> + <PredicateReferences MatchAtLeast="3"> + <PredicateReference Id="Lowercase"/> + <PredicateReference Id="Uppercase"/> + <PredicateReference Id="Number"/> + <PredicateReference Id="Symbol"/> + </PredicateReferences> + </PredicateGroup> + </PredicateGroups> + </PredicateValidation> + <PredicateValidation Id="CustomPassword"> + <PredicateGroups> + <PredicateGroup Id="DisallowedWhitespaceGroup"> + <PredicateReferences> + <PredicateReference Id="DisallowedWhitespace"/> + </PredicateReferences> + </PredicateGroup> + <PredicateGroup Id="AllowedCharactersGroup"> + <PredicateReferences> + <PredicateReference Id="AllowedCharacters"/> + </PredicateReferences> + </PredicateGroup> + </PredicateGroups> + </PredicateValidation> + ``` + We've three defined Predicate Validation, *StrongPassword*, *CustomPassword* and *SimplePassword*. Depending on the characteristics of the password you want your users to input, you can use any on the Predicate Validations. In this article, we'll use a strong password. ++1. Locate the *password* Claim Type declaration and add the *StrongPassword* Predicate Validation just after the UserInputType element declaration it contains by using the following code: ++ ```xml + <PredicateValidationReference Id="StrongPassword" /> + ``` +1. Locate the technical profile with `Id="UserInformationCollector"`, add the *password* claim as display claim by using the following code: ++ ```xml + <DisplayClaim ClaimTypeReferenceId="password" Required="true"/> + ``` ++1. In the technical profile with `Id="UserInformationCollector"`, add the *password* claim as an output claim by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="password"/> + ``` ++> [!NOTE] +> For security reasons, we'll not add a users's password as a claim in the token generated by your policy. So, we don't add the password claim to the relying party element. ++## Step 4 - Validate password and confirm password ++You can require your users to input their password twice as a means to confirm that the user remembers the password they input. In this case, you must check that the values of the two entries match. Custom policy provides an easy way to achieve this requirement. The claim types *password* and *reenterPassword* are considered special, so when they're used to collect user inputs, the UI validates that the user correctly re-entered their password. ++Use the following steps to validate password re-enter in your custom policy: ++1. In your `ClaimsSchema` section of your `ContosoCustomPolicy.XML` file, declare *reenterPassword* claim just after the *password* claim by using the following code: ++ ```xml + <ClaimType Id="reenterPassword"> + <DisplayName>Confirm new password</DisplayName> + <DataType>string</DataType> + <AdminHelpText>Confirm new password</AdminHelpText> + <UserHelpText>Reenter password</UserHelpText> + <UserInputType>Password</UserInputType> + </ClaimType> + ``` +1. To collect password confirmation input from the user, locate the `UserInformationCollector` self-asserted technical profile, add *reenterPassword* claim as a display claim by using the following code: ++ ```xml + <DisplayClaim ClaimTypeReferenceId="reenterPassword" Required="true"/> + ``` +1. In your your `ContosoCustomPolicy.XML` file, locate the `UserInformationCollector` self-asserted technical profile, add *reenterPassword* claim as an output claim by using the following code: ++ ```xml + <OutputClaim ClaimTypeReferenceId="reenterPassword"/> + ``` ++## Step 5 - Upload custom policy file ++At this point, you've built your policy to address the first three approaches to user input validation. ++Follow the steps in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file). If you're uploading a file with same name as the one already in the portal, make sure you select **Overwrite the custom policy if it already exists**. ++## Step 6 - Test the custom policy ++1. Under **Custom policies**, select **B2C_1A_CONTOSOCUSTOMPOLICY**. +1. For **Select application** on the overview page of the custom policy, select the web application such as *webapp1* that you previously registered. Make sure that the **Select reply URL** value is set to`https://jwt.ms`. +1. Select **Run now** button. +1. Enter **Given Name** and **Surname**. +1. Select **Account Type**. +1. For **Email Address**, enter an email value that's not well formatted such as *maurice@contoso*. +1. For **Password**, enter password value that doesn't obey all the characteristics of a strong password as set. +1. Select **Continue** button. You'll see a screen similar to the one shown below: ++ :::image type="content" source="media/custom-policies-series-validate-user-input/screenshot-of-user-input-validation.png" alt-text="screenshot of validating user inputs."::: ++ You must correct your inputs before you continue. ++1. Enter correct values as suggested by the error messages, and then select **Continue** button again. After the policy finishes execution, you're redirected to `https://jwt.ms`, and you see a decoded JWT token. The token looks similar to the following JWT token snippet: ++```json + { + "typ": "JWT", + "alg": "RS256", + "kid": "pxLOMWFg...." + }.{ + ... + "sub": "c7ae4515-f7a7....", + ... + "acr": "b2c_1a_contosocustompolicy", + "accountType": "work", + ... + "email": "maurice@contoso.com", + "name": "Maurice Paulet", + "message": "Hello Maurice Paulet" + }.[Signature] +``` ++## Step 7 - Validate user input by using validation technical profiles ++The validation techniques we've used in step 1, step 2 and step 3 aren't applicable for all scenarios. If your business rules are complex to be defined at claim declaration level, you can configure a [Validation Technical](validation-technical-profile.md), and then call it from a [Self-Asserted Technical Profile](self-asserted-technical-profile.md). ++> [!NOTE] +> Only self-asserted technical profiles can use validation technical profiles. Learn more about [validation technical profile](validation-technical-profile.md) + +### Scenario overview ++We require that, if the user's *Account Type* is *Contoso Employee Account*, we must ensure that their email domain is based on a set of predefined domains. These domains are *contoso.com, fabrikam.com*, and *woodgrove.com*. Otherwise, we show an error to the user until they use a valid *Contoso Employee Account* or switch to *Personal Account*. ++Use the following steps to learn how to validate user input by using validation technical profiles. You use a claims transformation type validation technical profile, but you can also call a REST API service to validate data as you'll learn later in this series. ++1. In your `ClaimsSchema` section of your `ContosoCustomPolicy.XML` file, declare *domain* and *domainStatus* claims by using the following code: ++ ```xml + <ClaimType Id="domain"> + <DataType>string</DataType> + </ClaimType> + + <ClaimType Id="domainStatus"> + <DataType>string</DataType> + </ClaimType> + ``` +1. Locate the `ClaimsTransformations` section, and configure claims transformations by using the following code: ++ ```xml + <ClaimsTransformation Id="GetDomainFromEmail" TransformationMethod="ParseDomain"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="emailAddress"/> + </InputClaims> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="domain" TransformationClaimType="domain"/> + </OutputClaims> + </ClaimsTransformation> + <ClaimsTransformation Id="LookupDomain" TransformationMethod="LookupValue"> + <InputClaims> + <InputClaim ClaimTypeReferenceId="domain" TransformationClaimType="inputParameterId"/> + </InputClaims> + <InputParameters> + <InputParameter Id="contoso.com" DataType="string" Value="valid"/> + <InputParameter Id="fabrikam.com" DataType="string" Value="valid"/> + <InputParameter Id="woodgrove.com" DataType="string" Value="valid"/> + <InputParameter Id="errorOnFailedLookup" DataType="boolean" Value="true"/> + </InputParameters> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="domainStatus" TransformationClaimType="outputClaim"/> + </OutputClaims> + </ClaimsTransformation> + ``` + + The *GetDomainFromEmail* claims transformation extracts a domain from email by using [ParseDomain](string-transformations.md#parsedomain) method and stores it in the *domain* claim. The *LookupDomain* Claims Transformation uses the extracted domain to check if it's valid by looking it up in the predefined domains, and assigning *valid* to *domainStatus* claim. ++1. Use the following code to add a technical profile in the same claims provider as the technical profile with `Id=UserInformationCollector`: ++ ```xml + <TechnicalProfile Id="CheckCompanyDomain"> + <DisplayName>Check Company validity </DisplayName> + <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> + <InputClaimsTransformations> + <InputClaimsTransformation ReferenceId="GetDomainFromEmail"/> + </InputClaimsTransformations> + <OutputClaims> + <OutputClaim ClaimTypeReferenceId="domain"/> + </OutputClaims> + <OutputClaimsTransformations> + <OutputClaimsTransformation ReferenceId="LookupDomain"/> + </OutputClaimsTransformations> + </TechnicalProfile> + ``` + We've declared claims transformation technical profile, which executes the *GetDomainFromEmail* and *LookupDomain* claims transformations. ++1. Locate the technical profile with `Id=UserInformationCollector`, and a `ValidationTechnicalProfile` just after the `OutputClaims` element by using the following code: ++ ```xml + <ValidationTechnicalProfiles> + <ValidationTechnicalProfile ReferenceId="CheckCompanyDomain"> + <Preconditions> + <Precondition Type="ClaimEquals" ExecuteActionsIf="false"> + <Value>accountType</Value> + <Value>work</Value> + <Action>SkipThisValidationTechnicalProfile</Action> + </Precondition> + </Preconditions> + </ValidationTechnicalProfile> + </ValidationTechnicalProfiles> + ``` + + We've added a Validation Technical Profile to the *UserInformationCollector* self-asserted technical profile. The technical profile is skipped only if the *accountType* value isn't equal to *work*. If the technical profile executes, and the email domain isn't valid, an error it thrown. ++1. Locate the technical profile with `Id=UserInformationCollector`, and add the following code inside the `metadata` tag. + + ```xml + <Item Key="LookupNotFound">The provided email address isn't a valid Contoso Employee email.</Item> + ``` + + We've set up a custom error in case the user doesn't use a valid email. ++1. Follow the instructions in [Upload custom policy file](custom-policies-series-hello-world.md#step-3upload-custom-policy-file) to upload your policy file. ++1. Follow the instructions in [step 6](#step-6test-the-custom-policy) to test your custom policy: + 1. For **Account Type**, select **Contoso Employee Account** + 1. For **Email Address**, enter an invalid email address such as *maurice@fourthcoffee.com*. + 1. Enter the rest of the details as required and select **Continue** + + Since *maurice@fourthcoffee.com* isn't a valid email, you'll see an error similar to the one shown in the screenshot below. You must use a valid email address to successfully run the custom policy and receive a JWT token. ++ :::image type="content" source="media/custom-policies-series-validate-user-input/screenshot-of-error-due-to-invalid-email-address.png" alt-text="screenshot of error due to invalid email address."::: ++## Next steps ++- Learn about [validation technical profile](validation-technical-profile.md). ++- Learn how to [Conditionally enable or disable Technical Profiles in Azure AD B2C custom policies](custom-policies-series-branch-user-journey.md) + |
active-directory-b2c | Deploy Custom Policies Github Action | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/deploy-custom-policies-github-action.md | To create a workflow, follow these steps: | Section| Name | Value | | - | -- |-- | | `env` | `clientId` | **Application (client) ID** of the application you registered in the [Register an MS Graph application](#register-a-microsoft-graph-application) step. |- |`env`| `tenant` | Your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, contoso.onmicrosoft.com). | + |`env`| `tenant` | Your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, contoso.onmicrosoft.com). | | `with`| `folder`| A folder where the custom policies files are stored, for example, `./Policies`.| | `with`| `files` | Comma-delimited list of policy files to deploy, for example, `TrustFrameworkBase.xml,TrustFrameworkLocalization.xml,TrustFrameworkExtensions.xml,SignUpOrSignin.xml`.| |
active-directory-b2c | Enable Authentication Azure Static App Options | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-azure-static-app-options.md | To use a custom domain and your tenant ID in the authentication URL, follow the In the configuration file, follow these steps: 1. Under the `customOpenIdConnectProviders` locate the `wellKnownOpenIdConfiguration` element.-1. Update the URL of your Azure AD B2C well-Known configuration endpoint with your custom domain and [tenant ID](tenant-management.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). +1. Update the URL of your Azure AD B2C well-Known configuration endpoint with your custom domain and [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). The following JSON shows the app settings before the change: |
active-directory-b2c | Enable Authentication In Node Web App Options | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-in-node-web-app-options.md | To use a custom domain and your tenant ID in the authentication URL, follow the In the *.env* file, do the following: - Replace all instances of `tenant-name.b2clogin.com` with your custom domain. For example, replace `tenant-name.b2clogin.com`, to `login.contoso.com`.-- Replace all instances of `tenant-name.onmicrosoft.com` with your [tenant ID](tenant-management.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id).+- Replace all instances of `tenant-name.onmicrosoft.com` with your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). The following configuration shows the app settings before the change: |
active-directory-b2c | Enable Authentication In Node Web App With Api Options | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-in-node-web-app-with-api-options.md | To use a custom domain and your tenant ID in the authentication URL, follow the In the `.env` file of your web app, do the following: - Replace all instances of `tenant-name.b2clogin.com` with your custom domain. For example, replace `tenant-name.b2clogin.com`, to `login.contoso.com`.-- Replace all instances of `tenant-name.onmicrosoft.com` with your [tenant ID](tenant-management.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id).+- Replace all instances of `tenant-name.onmicrosoft.com` with your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). The following configuration shows the app settings before the change: In the `index.js` file of your web API, do the following: - Replace all instances of `tenant-name.b2clogin.com` with your custom domain. For example, replace `tenant-name.b2clogin.com`, to `login.contoso.com`. -- Replace all instances of `tenant-name.onmicrosoft.com` with your [tenant ID](tenant-management.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id).+- Replace all instances of `tenant-name.onmicrosoft.com` with your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). The following configuration shows the app settings before the change: |
active-directory-b2c | Enable Authentication In Node Web App With Api | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-in-node-web-app-with-api.md | Add configurations to a configuration file. The file contains information about |Section |Key |Value | ||||-| credentials | tenantName | The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `fabrikamb2c`).| +| credentials | tenantName | The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `fabrikamb2c`).| | credentials |clientID | The web API application ID. To learn how to get your web API application registration ID, see [Prerequisites](#prerequisites). | | policies | policyName | The user flows, or custom policy. To learn how to get your user flow or policy, see [Prerequisites](#prerequisites).| | resource | scope | The scopes of your web API application registration such as `[tasks.read]`. To learn how to get your web API scope, see [Prerequisites](#prerequisites).| |
active-directory-b2c | Enable Authentication Ios App Options | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-ios-app-options.md | To use a custom domain and your tenant ID in the authentication URL, do the foll 1. Follow the guidance in [Enable custom domains](custom-domain.md). 1. Update the `kAuthorityHostName` class member with your custom domain.-1. Update the `kTenantName` class member with your [tenant ID](tenant-management.md#get-your-tenant-id). +1. Update the `kTenantName` class member with your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). The following Swift code shows the app settings before the change: |
active-directory-b2c | Enable Authentication Spa App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-spa-app.md | To specify your Azure AD B2C user flows, do the following: 1. Replace `B2C_1_SUSI` with your sign-in Azure AD B2C Policy name. 1. Replace `B2C_1_EditProfile` with your edit profile Azure AD B2C policy name.-1. Replace all instances of `contoso` with your [Azure AD B2C tenant name](./tenant-management.md#get-your-tenant-name). +1. Replace all instances of `contoso` with your [Azure AD B2C tenant name](./ tenant-management-read-tenant-name.md#get-your-tenant-name). ## Step 7: Use the MSAL to sign in the user |
active-directory-b2c | Enable Authentication Web Api | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-web-api.md | In the *appsettings.json* file, update the following properties: |Section |Key |Value | ||||-|AzureAdB2C|Instance| The first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| -|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| +|AzureAdB2C|Instance| The first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`).| +|AzureAdB2C|Domain| Your Azure AD B2C tenant full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| |AzureAdB2C|ClientId| The web API application ID. In the [preceding diagram](#app-registration-overview), it's the application with *App ID: 2*. To learn how to get your web API application registration ID, see [Prerequisites](#prerequisites). | |AzureAdB2C|SignUpSignInPolicyId|The user flows, or custom policy. To learn how to get your user flow or policy, see [Prerequisites](#prerequisites). | In the *config.json* file, update the following properties: |Section |Key |Value | ||||-| credentials | tenantName | Your Azure AD B2C [tenant name/domain name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| +| credentials | tenantName | Your Azure AD B2C [tenant name/domain name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`).| | credentials |clientID | The web API application ID. In the [preceding diagram](#app-registration-overview), it's the application with *App ID: 2*. To learn how to get your web API application registration ID, see [Prerequisites](#prerequisites). |-| credentials | issuer| The token issuer `iss` claim value. By default, Azure AD B2C returns the token in the following format: `https://<your-tenant-name>.b2clogin.com/<your-tenant-ID>/v2.0/`. Replace `<your-tenant-name>` with the first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name). Replace `<your-tenant-ID>` with your [Azure AD B2C tenant ID](tenant-management.md#get-your-tenant-id). | +| credentials | issuer| The token issuer `iss` claim value. By default, Azure AD B2C returns the token in the following format: `https://<your-tenant-name>.b2clogin.com/<your-tenant-ID>/v2.0/`. Replace `<your-tenant-name>` with the first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). Replace `<your-tenant-ID>` with your [Azure AD B2C tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). | | policies | policyName | The user flows, or custom policy. To learn how to get your user flow or policy, see [Prerequisites](#prerequisites).| | resource | scope | The scopes of your web API application registration. To learn how to get your web API scope, see [Prerequisites](#prerequisites).| |
active-directory-b2c | Enable Authentication Web App With Api Options | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-web-app-with-api-options.md | This article describes ways you can customize and enhance the Azure Active Direc To use a custom domain and your tenant ID in the authentication URL, follow the guidance in [Enable custom domains](custom-domain.md). Under the project root folder, open the `appsettings.json` file. This file contains information about your Azure AD B2C identity provider. - Update the `Instance` entry with your custom domain.-- Update the `Domain` entry with your [tenant ID](tenant-management.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id).+- Update the `Domain` entry with your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). The app settings *before* the change are shown in the following JSON code: |
active-directory-b2c | Enable Authentication Web Application Options | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-web-application-options.md | To use a custom domain and your tenant ID in the authentication URL, follow the In the *appsettings.json* file, do the following: - Update the `Instance` entry with your custom domain.-- Update the `Domain` entry with your [tenant ID](tenant-management.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id).+- Update the `Domain` entry with your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id). For more information, see [Use tenant ID](custom-domain.md#optional-use-tenant-id). The following JSON shows the app settings before the change: |
active-directory-b2c | Enable Authentication Web Application | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/enable-authentication-web-application.md | Azure AD B2C identity provider settings are stored in the *appsettings.json* fil The required information is described in the [Configure authentication in a sample web app](configure-authentication-sample-web-app.md) article. Use the following settings: -* **Instance**: Replace `<your-tenant-name>` with the first part of your Azure AD B2C [tenant name](tenant-management.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`). -* **Domain**: Replace `<your-b2c-domain>` with your Azure AD B2C full [tenant name](tenant-management.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`). +* **Instance**: Replace `<your-tenant-name>` with the first part of your Azure AD B2C [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `https://contoso.b2clogin.com`). +* **Domain**: Replace `<your-b2c-domain>` with your Azure AD B2C full [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name) (for example, `contoso.onmicrosoft.com`). * **Client ID**: Replace `<web-app-application-id>` with the Application ID from [Step 2](configure-authentication-sample-web-app.md#step-2-register-a-web-application). * **Policy name**: Replace `<your-sign-up-in-policy>` with the user flows you created in [Step 1](configure-authentication-sample-web-app.md#step-1-configure-your-user-flow). |
active-directory-b2c | Find Help Open Support Ticket | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/find-help-open-support-ticket.md | If you're unable to find answers by using self-help resources, you can open an o 1. Under **3. Additional details** tab, fill out the required details accurately. For example: - 1. Your tenant ID or domain name. See how to find your [tenant ID](tenant-management.md#get-your-tenant-id) or [tenant name](tenant-management.md#get-your-tenant-name). + 1. Your tenant ID or domain name. See how to find your [tenant ID]( tenant-management-read-tenant-name.md#get-your-tenant-id) or [tenant name]( tenant-management-read-tenant-name.md#get-your-tenant-name). 1. The time and date when the problem occurred. |
active-directory-b2c | Implicit Flow Single Page Application | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/implicit-flow-single-page-application.md | The recommended way of supporting SPAs is [OAuth 2.0 Authorization code flow (wi Some frameworks, like [MSAL.js 1.x](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-core), only support the implicit grant flow. In these cases, Azure Active Directory B2C (Azure AD B2C) supports the OAuth 2.0 authorization implicit grant flow. The flow is described in [section 4.2 of the OAuth 2.0 specification](https://tools.ietf.org/html/rfc6749). In implicit flow, the app receives tokens directly from the Azure AD B2C authorize endpoint, without any server-to-server exchange. All authentication logic and session handling are done entirely in the JavaScript client with either a page redirect or a pop-up box. -Azure AD B2C extends the standard OAuth 2.0 implicit flow to more than simple authentication and authorization. Azure AD B2C introduces the [policy parameter](user-flow-overview.md). With the policy parameter, you can use OAuth 2.0 to add policies to your app, such as sign-up, sign-in, and profile management user flows. In the example HTTP requests in this article, we use **{tenant}.onmicrosoft.com** for illustration. Replace `{tenant}` with [the name of your tenant](tenant-management.md#get-your-tenant-name) if you've one. Also, you need to have [created a user flow](tutorial-create-user-flows.md?pivots=b2c-user-flow). +Azure AD B2C extends the standard OAuth 2.0 implicit flow to more than simple authentication and authorization. Azure AD B2C introduces the [policy parameter](user-flow-overview.md). With the policy parameter, you can use OAuth 2.0 to add policies to your app, such as sign-up, sign-in, and profile management user flows. In the example HTTP requests in this article, we use **{tenant}.onmicrosoft.com** for illustration. Replace `{tenant}` with [the name of your tenant]( tenant-management-read-tenant-name.md#get-your-tenant-name) if you've one. Also, you need to have [created a user flow](tutorial-create-user-flows.md?pivots=b2c-user-flow). We use the following figure to illustrate implicit sign-in flow. Each step is described in detail later in the article. |
active-directory-b2c | Openid Connect | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/openid-connect.md | client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6 | Parameter | Required | Description | | | -- | -- |-| {tenant} | Yes | Name of your [Azure AD B2C tenant](tenant-management.md#get-your-tenant-name). If you're using a [custom domain](custom-domain.md), replace `tenant.b2clogin.com` with your domain, such as `fabrikam.com`. | +| {tenant} | Yes | Name of your [Azure AD B2C tenant]( tenant-management-read-tenant-name.md#get-your-tenant-name). If you're using a [custom domain](custom-domain.md), replace `tenant.b2clogin.com` with your domain, such as `fabrikam.com`. | | {policy} | Yes | The user flow or policy to be run. Specify the name of a user flow you've created in your Azure AD B2C tenant. For example: `b2c_1_sign_in`, `b2c_1_sign_up`, or `b2c_1_edit_profile`. | | client_id | Yes | The application ID that the [Azure portal](https://portal.azure.com/) assigned to your application. | | nonce | Yes | A value included in the request (generated by the application) that is included in the resulting ID token as a claim. The application can then verify this value to mitigate token replay attacks. The value is typically a randomized unique string that can be used to identify the origin of the request. | |
active-directory-b2c | Tenant Management Check Tenant Creation Permission | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/tenant-management-check-tenant-creation-permission.md | + + Title: Review tenant creation permission in Azure Active Directory B2C ++description: Learn how to check tenant creation permission in Azure Active Directory B2C before you create tenant ++++++++ Last updated : 01/30/2023++++++# Review tenant creation permission in Azure Active Directory B2C ++Anyone who creates an Azure Active Directory B2C (Azure AD B2C) becomes the *Global Administrator* of the tenant. It's a security risk if a non-admin user is allowed to create a tenant. In this article, you learn how, as an admin, you can restrict tenant creation for non-admins. Also, you'll learn how, as a non-admin user, you can check if you've permission to create a tenant. ++## Prerequisites ++- If you haven't already created your own [Azure AD B2C Tenant](tutorial-create-tenant.md), create one now. You can use an existing Azure AD B2C tenant. ++## Restrict non-admin users from creating Azure AD B2C tenants (preview) ++As a *Global Administrator* in an Azure AD B2C tenant, you can restrict non-admin users from creating tenants. To do so, use the following steps: ++1. Sign in to the [Azure portal](https://portal.azure.com). ++1. Make sure you're using the directory that contains your Azure AD B2C tenant: + + 1. Select the **Directories + subscriptions** icon in the portal toolbar. + + 1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. ++1. In the Azure portal, search for and select **Azure Active Directory**. ++1. Under **Manage**, select **User Settings**. ++1. Under **Tenant creation**, select **Yes**. ++1. At the top of the **User Settings** page, select **Save**. ++## Check tenant creation permission (preview) ++Before you create an Azure AD B2C tenant, make sure that you've the permission to do so. Use these steps to check that you've the permission to create a tenant: ++1. Sign in to the [Azure portal](https://portal.azure.com). ++1. Make sure you're using the directory that contains your Azure AD B2C tenant: + + 1. Select the **Directories + subscriptions** icon in the portal toolbar. + + 1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. ++1. In the Azure portal, search for and select **Azure Active Directory**. ++1. Under **Manage**, select **User Settings**. ++1. Review your **Tenant Creation** setting. If the settings is set to **No**, then contact your administrator to assign the tenant creator role to you. The setting is greyed out if you're not an administrator in the tenant. +++## Next steps ++- [Read tenant name and ID](tenant-management-read-tenant-name.md) +- [Clean up resources and delete tenant](tutorial-delete-tenant.md) |
active-directory-b2c | Tenant Management Emergency Access Account | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/tenant-management-emergency-access-account.md | + + Title: Manage emergency access accounts in Azure Active Directory B2C ++description: Learn how to manage emergency access accounts in Azure AD B2C tenants +++++++ Last updated : 01/30/2023+++++++# Manage emergency access accounts in Azure Active Directory B2C ++It's important that you prevent being accidentally locked out of your Azure Active Directory B2C (Azure AD B2C) organization because you can't sign in or activate another user's account as an administrator. You can mitigate the impact of accidental lack of administrative access by creating two or more *emergency access accounts* in your organization. ++When you configure these accounts, the following requirements need to be met: ++- The emergency access accounts shouldn't be associated with any individual user in the organization. Make sure that your accounts aren't connected with any employee-supplied mobile phones, hardware tokens that travel with individual employees, or other employee-specific credentials. This precaution covers instances where an individual employee is unreachable when the credential is needed. It's important to ensure that any registered devices are kept in a known, secure location that has multiple means of communicating with Azure AD B2C. ++- Use strong authentication for your emergency access accounts and make sure it doesnΓÇÖt use the same authentication methods as your other administrative accounts. For example, if your normal administrator account uses the Microsoft Authenticator app for strong authentication, use a FIDO2 security key for your emergency accounts. ++- The device or credential must not expire or be in scope of automated cleanup due to lack of use. ++## Prerequisites ++- If you haven't already created your own [Azure AD B2C Tenant](tutorial-create-tenant.md), create one now. You can use an existing Azure AD B2C tenant. +- Understand [user accounts in Azure AD B2C](user-overview.md). +- Understand [user roles to control resource access](roles-resource-access-control.md). +- Understand [Conditional Access](conditional-access-user-flow.md) ++## Create emergency access account ++Create two or more emergency access accounts. These accounts should be cloud-only accounts that use the *.onmicrosoft.com* domain and that aren't federated or synchronized from an on-premises environment. ++Use the following steps to create an emergency access account: ++1. Sign in to the [Azure portal](https://portal.azure.com) as an existing Global Administrator. If you use your Azure AD account, make sure you're using the directory that contains your Azure AD B2C tenant: ++ 1. Select the **Directories + subscriptions** icon in the portal toolbar. + + 1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. + +1. Under **Azure services**, select **Azure AD B2C**. Or in the Azure portal, search for and select **Azure AD B2C**. ++1. In the left menu, under **Manage**, select **Users**. ++1. Select **+ New user**. ++1. Select **Create user**. ++1. Under **Identity**: ++ 1. For **User name**, enter a unique user name such as *emergency account*. + + 1. For **Name**, enter a name such as *Emergency Account* + +1. Under **Password**, enter your unique password. + +1. Under **Groups and roles** + + 1. Select **User**. ++ 1. In the pane that shows up, search for and select **Global administrator**, and then select **Select** button. ++1. Under **Settings**, select the appropriate **Usage location**. ++1. Select **Create**. ++1. [Store account credentials safely](../active-directory/roles/security-emergency-access.md#store-account-credentials-safely). ++1. [Monitor sign in and audit logs](../active-directory/roles/security-emergency-access.md#monitor-sign-in-and-audit-logs). ++1. [Validate accounts regularly](../active-directory/roles/security-emergency-access.md#validate-accounts-regularly). ++Once you create your emergency accounts, you need to do the following: ++- Make sure you [exclude at least one account from phone-based multi-factor authentication](../active-directory/roles/security-emergency-access.md#exclude-at-least-one-account-from-phone-based-multi-factor-authentication) ++- If you use [Conditional Access](conditional-access-user-flow.md), at least one emergency access account needs to be excluded from all conditional access policies. ++## Next steps ++- [Read tenant name and ID](tenant-management-read-tenant-name.md) +- [Clean up resources and delete tenant](tutorial-delete-tenant.md) + |
active-directory-b2c | Tenant Management Manage Administrator | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/tenant-management-manage-administrator.md | + + Title: Manage administrator accounts in Azure Active Directory B2C ++description: Learn how to add an administrator account to your Azure Active Directory B2C tenant. Learn how to invite a guest account as an administrator into your Azure AD B2C tenant. ++++++++ Last updated : 01/30/2023++++++# Manage administrator accounts in Azure Active Directory B2C ++In Azure Active Directory B2C (Azure AD B2C), a tenant represents your directory of consumer, work and guest accounts. With an administrator role, work and guest accounts can manage the tenant. ++In this article, you learn how to: ++> [!div class="checklist"] +> * Add an administrator (work account) +> * Invite an administrator (guest account) +> * Add role assignment to a user account +> * Remove a role assignment from a user account +> * Delete an administrator account +> * Protect administrative accounts ++## Prerequisites +- If you haven't already created your own [Azure AD B2C Tenant](tutorial-create-tenant.md), create one now. You can use an existing Azure AD B2C tenant. +- Understand [user accounts in Azure AD B2C](user-overview.md). +- Understand [user roles to control resource access](roles-resource-access-control.md). ++## Add an administrator (work account) ++To create a new administrative account, follow these steps: ++1. Sign in to the [Azure portal](https://portal.azure.com/) with Global Administrator or Privileged Role Administrator permissions. +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. Under **Azure services**, select **Azure AD B2C**. Or use the search box to find and select **Azure AD B2C**. +1. Under **Manage**, select **Users**. +1. Select **New user**. +1. Select **Create user** (you can create many users at once by selecting **I want to create users in bulk**). +1. On the **User** page, enter information for this user: ++ + - **User name**. *Required*. The user name of the new user. For example, `mary@contoso.com`. + The domain part of the user name must use either the initial default domain name, *\<tenant name>.onmicrosoft.com* or your [custom domain](custom-domain.md) such as `contoso.com`. + - **Name**. *Required*. The first and last name of the new user. For example, *Mary Parker*. + - **Groups**. *Optional*. You can add the user to one or more existing groups. You can also add the user to groups at a later time. + - **Directory role**: If you require Azure AD administrative permissions for the user, you can add them to an Azure AD role. You can assign the user to be a Global administrator or one or more of the limited administrator roles in Azure AD. For more information about assigning roles, see [Use roles to control resource access](roles-resource-access-control.md). + - **Job info**: You can add more information about the user here, or do it later. ++1. Copy the autogenerated password provided in the **Password** box. You'll need to give this password to the user to sign in for the first time. +1. Select **Create**. ++The user is created and added to your Azure AD B2C tenant. It's preferable to have at least one work account native to your Azure AD B2C tenant assigned the Global Administrator role. This account can be considered a *break-glass account* or *[emergency access accounts](tenant-management-emergency-access-account.md)*. ++## Invite an administrator (guest account) ++You can also invite a new guest user to manage your tenant. The guest account is the preferred option when your organization also has Azure AD because the lifecycle of this identity can be managed externally. ++To invite a user, follow these steps: ++1. Sign in to the [Azure portal](https://portal.azure.com/) with Global Administrator or Privileged Role Administrator permissions. +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. Under **Azure services**, select **Azure AD B2C**. Or use the search box to find and select **Azure AD B2C**. +1. Under **Manage**, select **Users**. +1. Select **New guest account**. +1. On the **User** page, enter information for this user: ++ - **Name**. *Required*. The first and last name of the new user. For example, *Mary Parker*. + - **Email address**. *Required*. The email address of the user you would like to invite, which must be a Microsoft account. For example, `mary@contoso.com`. + - **Personal message**: You add a personal message that will be included in the invite email. + - **Groups**. *Optional*. You can add the user to one or more existing groups. You can also add the user to groups at a later time. + - **Directory role**: If you require Azure AD administrative permissions for the user, you can add them to an Azure AD role. You can assign the user to be a Global administrator or one or more of the limited administrator roles in Azure AD. For more information about assigning roles, see [Use roles to control resource access](roles-resource-access-control.md). + - **Job info**: You can add more information about the user here, or do it later. ++1. Select **Create**. ++An invitation email is sent to the user. The user needs to accept the invitation to be able to sign in. ++### Resend the invitation email ++If the guest didn't receive the invitation email, or the invitation expired, you can resend the invite. As an alternative to the invitation email, you can give a guest a direct link to accept the invitation. To resend the invitation and get the direct link: ++1. Sign in to the [Azure portal](https://portal.azure.com). +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. Under **Azure services**, select **Azure AD B2C**. Or use the search box to find and select **Azure AD B2C**. +1. Under **Manage**, select **Users**. +1. Search for and select the user you want to resend the invite to. +1. In the **User | Profile** page, under **Identity**, select **(Manage)**. +  ++1. For **Resend invite?**, select **Yes**. When **Are you sure you want to resend an invitation?** appears, select **Yes**. +1. Azure AD B2C sends the invitation. You can also copy the invitation URL and provide it directly to the guest. + +  + +## Add a role assignment ++You can assign a role when you [create a user](#add-an-administrator-work-account) or [invite a guest user](#invite-an-administrator-guest-account). You can add a role, change the role, or remove a role for a user: ++1. Sign in to the [Azure portal](https://portal.azure.com/) with Global Administrator or Privileged Role Administrator permissions. +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. Under **Azure services**, select **Azure AD B2C**. Or use the search box to find and select **Azure AD B2C**. +1. Under **Manage**, select **Users**. +1. Select the user you want to change the roles for. Then select **Assigned roles**. +1. Select **Add assignments**, select the role to assign (for example, *Application administrator*), and then choose **Add**. ++## Remove a role assignment ++If you need to remove a role assignment from a user, follow these steps: ++1. Select **Azure AD B2C**, select **Users**, and then search for and select the user. +1. Select **Assigned roles**. Select the role you want to remove, for example *Application administrator*, and then select **Remove assignment**. ++## Review administrator account role assignments ++As part of an auditing process, you typically review which users are assigned to specific roles in the Azure AD B2C directory. Use the following steps to audit which users are currently assigned privileged roles. ++1. Sign in to the [Azure portal](https://portal.azure.com/) with Global Administrator or Privileged Role Administrator permissions. +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. Under **Azure services**, select **Azure AD B2C**. Or use the search box to find and select **Azure AD B2C**. +1. Under **Manage**, select **Roles and administrators**. +1. Select a role, such as **Global administrator**. The **Role | Assignments** page lists the users with that role. ++## Delete an administrator account ++To delete an existing user, you must have a *Global administrator* role assignment. Global admins can delete any user, including other admins. *User administrators* can delete any non-admin user. ++1. In your Azure AD B2C directory, select **Users**, and then select the user you want to delete. +1. Select **Delete**, and then **Yes** to confirm the deletion. ++The user is deleted and no longer appears on the **Users - All users** page. The user can be seen on the **Deleted users** page for the next 30 days and can be restored during that time. For more information about restoring a user, see [Restore or remove a recently deleted user using Azure Active Directory](../active-directory/fundamentals/active-directory-users-restore.md). ++## Protect administrative accounts ++It's recommended that you protect all administrator accounts with multifactor authentication (MFA) for more security. MFA is an identity verification process during sign in that prompts the user for a more form of identification, such as a verification code on their mobile device or a request in their Microsoft Authenticator app. ++ ++If you're not using [Conditional Access](conditional-access-user-flow.md), you can enable [Azure AD security defaults](../active-directory/fundamentals/concept-fundamentals-security-defaults.md) to force all administrative accounts to use MFA. ++## Next steps ++- [Manage emergency access accounts in Azure Active Directory B2C](tenant-management-emergency-access-account.md) |
active-directory-b2c | Tenant Management Read Tenant Name | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/tenant-management-read-tenant-name.md | + + Title: Find tenant name and tenant ID ++description: Learn how to find tenant name and tenant ID +++++++ Last updated : 01/30/2023+++++++# Find tenant name and tenant ID in Azure Active Directory B2C ++When you create an Azure Active Directory B2C (Azure AD B2C) for your organization, it's assigned a default domain name (name) and an ID. The tenant ID is same as the organization ID. ++In this article, you learn how to: ++> [!div class="checklist"] +> * Find and copy your tenant name +> * Find and copy your tenant ID ++## Prerequisites ++- If you haven't already created your own [Azure AD B2C Tenant](tutorial-create-tenant.md), create one now. You can use an existing Azure AD B2C tenant. +++## Get your tenant name ++To get your Azure AD B2C tenant name, follow these steps: ++1. Sign in to the [Azure portal](https://portal.azure.com). +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. In the Azure portal, search for and select **Azure AD B2C**. +1. In the **Overview**, copy the **Domain name**. ++ ++## Get your tenant ID ++To get your Azure AD B2C tenant ID, follow these steps: ++1. Sign in to the [Azure portal](https://portal.azure.com). +1. Make sure you're using the directory that contains your Azure AD B2C tenant. Select the **Directories + subscriptions** icon in the portal toolbar. +1. On the **Portal settings | Directories + subscriptions** page, find your Azure AD B2C directory in the **Directory name** list, and then select **Switch**. +1. In the Azure portal, search for and select **Azure Active Directory**. +1. In the **Overview**, copy the **Tenant ID**. ++ ++## Next steps ++- [Clean up resources and delete tenant](tutorial-delete-tenant.md) |
active-directory-b2c | Troubleshoot | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/troubleshoot.md | This article focuses on troubleshooting your Azure AD B2C custom policy configur ## Azure AD B2C correlation ID overview -Azure AD B2C correlation ID is a unique identifier value that is attached to authorization requests. It passes through all the orchestration steps a user is taken through. With the correlation ID, you can: +Azure AD B2C correlation ID is a unique identifier value that is attached to authorization requests. It passes through all the orchestration steps that a user goes through. With the correlation ID, you can: - Identify sign-in activity in your application and track the performance of your policy. - Find the sign-in request's Azure Application Insights logs. Azure AD B2C correlation ID is a unique identifier value that is attached to aut The correlation ID is changed every time a new session is established. When you debug your policies, make sure that you close existing browser tabs or open a new in-private mode browser. +## Prerequisites ++- Complete the steps in [Get started with custom policies in Active Directory B2C](tutorial-create-user-flows.md?pivots=b2c-custom-policy). + ### Get the Azure AD B2C correlation ID You can find the correlation ID in the Azure AD B2C sign-up or sign-in page. In your browser, select **view source**. The correlation appears as a comment at the top of the page. The following screenshot shows the Azure AD B2C extension for VS Code with Azure ### Filter the trace log -With the focus on the Azure AD B2C trace explorer, start to type the first digit of the correlation ID, or a time you want to find. You will see a filter box in the top-right of the Azure AD B2C trace explorer showing what you have typed so far, and matching trace logs will be highlighted. +With the focus on the Azure AD B2C trace explorer, start to type the first digit of the correlation ID, or a time you want to find. You'll see a filter box in the top-right of the Azure AD B2C trace explorer showing what you have typed so far, and matching trace logs will be highlighted.  You can also trace the exchange of messages between your client browser and Azur ## Troubleshoot policy validity -After you finish developing your policy, you upload the policy to Azure AD B2C. there might be some issues with your policy. Use the following methods to ensure your policy integrity/validity. +After you finish developing your policy, you upload the policy to Azure AD B2C. There might be some issues with your policy, but you can validity your policy before you upload it. The most common error in setting up custom policies is improperly formatted XML. A good XML editor is nearly essential. It displays XML natively, color-codes content, pre-fills common terms, keeps XML elements indexed, and can validate against an XML schema. We recommend using [Visual Studio Code](https://code.visualstudio.com/). Then in You can use the XML file association strategy to bind the XML file the XSD by adding the following settings into your VS Code `settings.json` file. To do so: -1. From VS Code, click on the **Settings**. For more information, see [User and Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings). +1. From VS Code, select **File>Preferences>Settings**. For more information, see [User and Workspace Settings](https://code.visualstudio.com/docs/getstarted/settings). 1. Search for **fileAssociations**, then under the **Extension**, select the **XML**. 1. Select **Edit in settings.json**. You can use the XML file association strategy to bind the XML file the XSD by ad } ] ```+1. Save the changes. The following example shows an XML validation error. When you move your mouse over the element name, the extension list the expected elements. |
active-directory-b2c | Tutorial Create Tenant | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/tutorial-create-tenant.md | Before you create your Azure AD B2C tenant, you need to take the following consi - You can create up to **20** tenants per subscription. This limit help protect against threats to your resources, such as denial-of-service attacks, and is enforced in both the Azure portal and the underlying tenant creation API. If you want to increase this limit, please contact [Microsoft Support](find-help-open-support-ticket.md). -- By default, each tenant can accommodate a total of **1.25 million** objects (user accounts and applications), but you can increase this limit to **5.25 million** objects when you add and verify a custom domain. If you want to increase this limit, please contact [Microsoft Support](find-help-open-support-ticket.md). However, if you created your tenant before **September 2022**, this limit doesn't affect you, and your tenant will retain the size allocated to it at creation, that's, **50 million** objects. +- By default, each tenant can accommodate a total of **1.25 million** objects (user accounts and applications), but you can increase this limit to **5.25 million** objects when you add and verify a custom domain. If you want to increase this limit, please contact [Microsoft Support](find-help-open-support-ticket.md). However, if you created your tenant before **September 2022**, this limit doesn't affect you, and your tenant will retain the size allocated to it at creation, that's, **50 million** objects. Learn how to [read your tenant usage](microsoft-graph-operations.md#tenant-usage). - If you want to reuse a tenant name that you previously tried to delete, but you see the error "Already in use by another directory" when you enter the domain name, you'll need to [follow these steps to fully delete the tenant first](./faq.yml?tabs=app-reg-ga#how-do-i-delete-my-azure-ad-b2c-tenant-). A role of at least *Subscription Administrator* is required. After deleting the tenant, you might also need to sign out and sign back in before you can reuse the domain name. Before you create your Azure AD B2C tenant, you need to take the following consi ## Create an Azure AD B2C tenant >[!NOTE]->If you're unable to create Azure AD B2C tenant, review your user settings page to ensure that tenant creation isn't switched off. If tenant creation is switched off, ask your _Global Administrator_ to assign you a _Tenant Creator_ role. +>If you're unable to create Azure AD B2C tenant, [review your user settings page](tenant-management-check-tenant-creation-permission.md) to ensure that tenant creation isn't switched off. If tenant creation is switched off, ask your _Global Administrator_ to assign you a _Tenant Creator_ role. 1. Sign in to the [Azure portal](https://portal.azure.com/). |
active-directory-b2c | Whats New Docs | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory-b2c/whats-new-docs.md | +## January 2023 ++### New articles ++- [Migrate applications using header-based authentication to Azure Active Directory B2C with Grit's app proxy](partner-grit-app-proxy.md) +- [Configure Grit's biometric authentication with Azure Active Directory B2C](partner-grit-authentication.md) ++### Updated articles ++- [Monitor Azure AD B2C with Azure Monitor](azure-monitor.md) +- [Set up sign-up and sign-in with a Twitter account using Azure Active Directory B2C](identity-provider-twitter.md) +- [Tutorial: Configure Azure Active Directory B2C with Datawiza to provide secure hybrid access](partner-datawiza.md) +- [Tutorial: Configure Ping Identity with Azure Active Directory B2C for secure hybrid access](partner-ping-identity.md) +- [Sign-in options in Azure AD B2C](sign-in-options.md) +- [Quickstart: Set up sign in for an ASP.NET application using Azure Active Directory B2C](quickstart-web-app-dotnet.md) +- [Enrich tokens with claims from external sources using API connectors](add-api-connector-token-enrichment.md) +- [Identity verification and proofing partners](identity-verification-proofing.md) +- [Configure complexity requirements for passwords in Azure Active Directory B2C](password-complexity.md) +- [User profile attributes](user-profile-attributes.md) +- [Azure Active Directory B2C: What's new](whats-new-docs.md) +- [Tutorial: Configure Azure Active Directory B2C with the Arkose Labs platform](partner-arkose-labs.md) +- [Tutorial: Configure Zscaler Private Access with Azure Active Directory B2C](partner-zscaler.md) +- [Tutorial to configure Azure Active Directory B2C with WhoIAM](partner-whoiam.md) +- [Tutorial to configure Azure Active Directory B2C with Strata](partner-strata.md) +- [Tutorial for configuring Onfido with Azure Active Directory B2C](partner-onfido.md) +- [Tutorial to configure Nevis with Azure Active Directory B2C for passwordless authentication](partner-nevis.md) +- [Tutorial for configuring LexisNexis with Azure Active Directory B2C](partner-lexisnexis.md) +- [Tutorial for configuring Jumio with Azure Active Directory B2C](partner-jumio.md) +- [Tutorial for configuring HYPR with Azure Active Directory B2C](partner-hypr.md) +- [Manage Azure AD B2C with Microsoft Graph](microsoft-graph-operations.md) +- [Tutorial: Create an Azure Active Directory B2C tenant](tutorial-create-tenant.md) +- [Build a global identity solution with funnel-based approach](azure-ad-b2c-global-identity-funnel-based-design.md) + ## December 2022 ### New articles |
active-directory | Known Issues | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/app-provisioning/known-issues.md | This article discusses known issues to be aware of when you work with app provis An external user from the source (home) tenant can't be provisioned into another tenant. Internal guest users from the source tenant can't be provisioned into another tenant. Only internal member users from the source tenant can be provisioned into the target tenant. For more information, see [Properties of an Azure Active Directory B2B collaboration user](../external-identities/user-properties.md). +In addition, users that are enabled for SMS sign-in cannot be synchronized through cross-tenant synchronization. + ### Provisioning manager attributes Provisioning manager attributes isn't supported. |
active-directory | How To Mfa Number Match | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/authentication/how-to-mfa-number-match.md | description: Learn how to use number matching in MFA notifications Previously updated : 01/20/2023 Last updated : 01/31/2023 This topic covers how to enable number matching in Microsoft Authenticator push >[!NOTE] >Number matching is a key security upgrade to traditional second factor notifications in Microsoft Authenticator. We will remove the admin controls and enforce the number match experience tenant-wide for all users starting February 27, 2023.<br> ->We highly recommend enabling number matching in the near term for improved sign-in security. +>We highly recommend enabling number matching in the near term for improved sign-in security. Relevant services will begin deploying these changes after February 27, 2023 and users will start to see number match in approval requests. As services deploy, some may see number match while others don't. To ensure consistent behavior for all users, we highly recommend you enable number match for Microsoft Authenticator push notifications in advance. ## Prerequisites Number matching can be targeted to only a single group, which can be dynamic or Number matching is available for the following scenarios. When enabled, all scenarios support number matching. -- [Multifactor authentication](tutorial-enable-azure-mfa.md)-- [Self-service password reset](howto-sspr-deployment.md)-- [Combined SSPR and MFA registration during Authenticator app set up](howto-registration-mfa-sspr-combined.md)-- [AD FS adapter](howto-mfaserver-adfs-windows-server.md)-- [NPS extension](howto-mfa-nps-extension.md)+- [Multifactor authentication](#multifactor-authentication) +- [Self-service password reset](#sspr) +- [Combined SSPR and MFA registration during Authenticator app set up](#combined-registration) +- [AD FS adapter](#ad-fs-adapter) +- [NPS extension](#nps-extension) Number matching isn't supported for Apple Watch notifications. Apple Watch users need to use their phone to approve notifications when number matching is enabled. ### Multifactor authentication -When a user responds to an MFA push notification using the Authenticator app, they'll be presented with a number. They need to type that number into the app to complete the approval. +When a user responds to an MFA push notification using the Authenticator app, they'll be presented with a number. They need to type that number into the app to complete the approval. For more information about how to set up MFA, see [Tutorial: Secure user sign-in events with Azure AD Multi-Factor Authentication](tutorial-enable-azure-mfa.md).  ### SSPR -Self-service password reset (SSPR) with Microsoft Authenticator will require number matching when using Microsoft Authenticator. During self-service password reset, the sign-in page will show a number that the user will need to type into the Microsoft Authenticator notification. This number will only be seen by users who are enabled for number matching. +Self-service password reset (SSPR) with Microsoft Authenticator will require number matching when using Microsoft Authenticator. During self-service password reset, the sign-in page will show a number that the user will need to type into the Microsoft Authenticator notification. This number will only be seen by users who are enabled for number matching. For more information about how to set up SSPR, see [Tutorial: Enable users to unlock their account or reset passwords](howto-sspr-deployment.md). ### Combined registration -Combined registration with Microsoft Authenticator will require number matching. When a user goes through combined registration to set up the Authenticator app, the user is asked to approve a notification as part of adding the account. For users who are enabled for number matching, this notification will show a number that they need to type in their Authenticator app notification. +Combined registration with Microsoft Authenticator will require number matching. When a user goes through combined registration to set up the Authenticator app, the user is asked to approve a notification as part of adding the account. For users who are enabled for number matching, this notification will show a number that they need to type in their Authenticator app notification. For more information about how to set up combined registration, see [Enable combined security information registration](howto-registration-mfa-sspr-combined.md). ### AD FS adapter -AD FS adapter will require number matching on supported versions of Windows Server. On earlier versions, users will continue to see the **Approve**/**Deny** experience and wonΓÇÖt see number matching until you upgrade. The AD FS adapter supports number matching only after installing one of the updates in the following table. +AD FS adapter will require number matching on supported versions of Windows Server. On earlier versions, users will continue to see the **Approve**/**Deny** experience and wonΓÇÖt see number matching until you upgrade. The AD FS adapter supports number matching only after installing one of the updates in the following table. For more information about how to set up AD FS adapter, see [Configure Azure Active Directory (Azure AD) Multi-Factor Authentication Server to work with AD FS in Windows Server](howto-mfaserver-adfs-windows-server.md). >[!NOTE] >Unpatched versions of Windows Server don't support number matching. Users will continue to see the **Approve**/**Deny** experience and won't see number matching unless these updates are applied. AD FS adapter will require number matching on supported versions of Windows Serv ### NPS extension -Make sure you run the latest version of the [NPS extension](https://www.microsoft.com/download/details.aspx?id=54688). Until February 27, 2023, users are asked to enter a One-Time Passcode (OTP) for push notifications beginning with NPS extension 1.2.2131.2 _only_ if number matching is enabled. After February 27, 2023, number matching will be enabled by default and all users with push notifications beginning with NPS extension 1.2.2131.2 will be asked to enter an OTP. +Although NPS doesn't support number matching, the latest NPS extension does support One-Time Password (OTP) methods such as the OTP available in Microsoft Authenticator, other software tokens, and hardware FOBs. OTP sign-in provides better security than the alternative **Approve**/**Deny** experience. Make sure you run the latest version of the [NPS extension](https://www.microsoft.com/download/details.aspx?id=54688). -The user must have an OTP authentication method registered to see this behavior. Common OTP authentication methods include the OTP available in Microsoft Authenticator, other software tokens, and so on. For OTP to work, the VPN needs to use PAP protocol. For more information, see [Determine which authentication methods your users can use](howto-mfa-nps-extension.md#determine-which-authentication-methods-your-users-can-use). +After Feb 27, 2023, when number matching is enabled for all users, anyone who performs a RADIUS connection with NPS extension version 1.2.2216.1 or later will be prompted to sign in with an OTP method instead. ->[!NOTE] ->If the user doesn't have an OTP method registered, they'll continue to get the **Approve**/**Deny** experience. A user who can't use an OTP will always see the **Approve**/**Deny** experience with push notifications triggered by a legacy NPS extension. +Users must have an OTP authentication method registered to see this behavior. Without an OTP method registered, users continue to see **Approve**/**Deny**. + +Prior to the release of NPS extension version 1.2.2216.1 after February 27, 2023, organizations that run any of these earlier versions of NPS extension can modify the registry to require users to enter an OTP: -Earlier versions of the NPS extension beginning with 1.0.1.40 also support number matching, but you need to create a registry key that overrides push notifications to ask a user to enter an OTP. If you don't create the registry key, or you run a version prior to 1.0.1.40, users who are enabled for number matching will be prompted to **Approve**/**Deny**. +- 1.2.2131.2 +- 1.2.1959.1 +- 1.2.1916.2 +- 1.1.1892.2 +- 1.0.1850.1 +- 1.0.1.41 +- 1.0.1.40 -To create the registry key that overrides push notifications: +>[!NOTE] +>NPS extensions versions earlier than 1.0.1.40 don't support OTP enforced by number matching. These versions will continue to present users with **Approve**/**Deny**. ++To create the registry key to override the **Approve**/**Deny** options in push notifications and require an OTP instead: 1. On the NPS Server, open the Registry Editor. 1. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\AzureMfa. To create the registry key that overrides push notifications: Value = TRUE 1. Restart the NPS Service. -If you're using Remote Desktop Gateway and the user is registered for OTP code along with Microsoft Authenticator push notifications, the user won't be able to meet the Azure AD MFA challenge and Remote Desktop Gateway sign-in will fail. In this case, you can set OVERRIDE_NUMBER_MATCHING_WITH_OTP = FALSE to fall back to push notifications with Microsoft Authenticator. +In addition: ++- Users who perform OTP must have either Microsoft Authenticator registered as an authentication method, or some other hardware or software OATH token. A user who can't use an OTP method will always see **Approve**/**Deny** options with push notifications if they use a version of NPS extension earlier than 1.2.2216.1. +- Users must be [enabled for number matching](#enable-number-matching-in-the-portal). +- The NPS Server where the NPS extension is installed must be configured to use PAP protocol. For more information, see [Determine which authentication methods your users can use](howto-mfa-nps-extension.md#determine-which-authentication-methods-your-users-can-use). ++ >[!IMPORTANT] + >MSCHAPv2 doesn't support OTP. If the NPS Server isn't configured to use PAP, user authorization will fail with events in the **AuthZOptCh** log of the NPS Extension server in Event Viewer:<br> + >NPS Extension for Azure MFA: Challenge requested in Authentication Ext for User npstesting_ap. ++If your organization uses Remote Desktop Gateway and the user is registered for OTP code along with Microsoft Authenticator push notifications, the user won't be able to meet the Azure AD MFA challenge and Remote Desktop Gateway sign-in will fail. In this case, you can set OVERRIDE_NUMBER_MATCHING_WITH_OTP = FALSE to fall back to **Approve**/**Deny** push notifications with Microsoft Authenticator. ### Apple Watch supported for Microsoft Authenticator GET https://graph.microsoft.com/beta/authenticationMethodsPolicy/authenticationM Number match will be enabled for all users of Microsoft Authenticator after February 27, 2023. Relevant services will begin deploying these changes after February 27, 2023 and users will start to see number match in approval requests. As services deploy, some may see number match while others don't. To ensure consistent behavior for all your users, we highly recommend you use the Azure portal or Graph API to roll out number match for all Microsoft Authenticator users. -### Will the changes on February 27th, 2023, override number matching settings that are configured for a group? +### Will the changes after February 27th, 2023, override number matching settings that are configured for a group in the Authentication methods policy? ++No, the changes after February 27th won't affect the **Enable and Target** tab for Microsoft Authenticator in the Authentication methods policy. Administrators can continue to target specific users and groups or **All Users** for Microsoft Authenticator **Push** or **Any** authentication mode. -The **Enable and Target** tab of the Microsoft Authenticator authentication method policy will remain unchanged. Admins can continue to Target specific users and groups or All Users for Push or Any notifications. This change will only impact members of users and groups that are Targeted on the **Enable and Target** tab for Push and/or Any. +When Microsoft begins protecting all organizations by enabling number matching after February 27th, 2023, administrators will see the **Require number matching for push notifications** setting on the **Configure** tab of the Microsoft Authenticator policy is set to **Enabled** for **All users** and can't be disabled. In addition, the **Exclude** option for this setting will be removed. -When Microsoft begins protecting all organizations by enabling number matching on February 27th, 2023, administrators will see the **Require number matching for push notifications** setting on the **Configure** tab of the Microsoft Authenticator policy is set to **Enabled** for **All users** and can't be disabled. In addition, the **Exclude** option for this setting will be removed. +### What happens for users who aren't specified in the Authentication methods policy but they are enabled for Notifications through mobile app in the legacy MFA tenant-wide policy? +Users who are enabled for MFA push notifications in the legacy MFA policy will also see number match after February 27th, 2023. If the legacy MFA policy has enabled **Notifications through mobile app**, users will see number matching regardless of whether or not it's enabled on the **Enable and Target** tab for Microsoft Authenticator in the Authentication methods policy. + ### How should users be prepared for default number matching? They'll see a prompt to supply a verification code. They must select their accou Yes, currently you can disable number matching. We highly recommend that you enable number matching for all users in your tenant to protect yourself from MFA fatigue attacks. To protect the ecosystem and mitigate these threats, Microsoft will enable number matching for all tenants starting February 27, 2023. After protection is enabled by default, users can't opt out of number matching in Microsoft Authenticator push notifications. +Relevant services will begin deploying these changes after February 27, 2023 and users will start to see number match in approval requests. As services deploy, some may see number match while others don't. To ensure consistent behavior for all users, we highly recommend you enable number match for Microsoft Authenticator push notifications in advance. + ### Does number matching only apply if Microsoft Authenticator is set as the default authentication method? -If the user has a different default authentication method, there won't be any change to their default sign-in. If the default method is Microsoft Authenticator and they are members of groups targeted for **Push** or **Any** on the **Enable and Target** tab, they'll start to receive number matching approval on February 27th, 2023. +If the user has a different default authentication method, there won't be any change to their default sign-in. If the default method is Microsoft Authenticator and the user is specified in either of the following policies, they'll start to receive number matching approval after February 27th, 2023: ++- Authentication methods policy (in the portal, click **Security** > **Authentication methods** > **Policies**) +- Legacy MFA tenant-wide policy (in the portal, click **Security** > **Multifactor Authentication** > **Additional cloud-based multifactor authentication settings**) -Regardless of their default method, any user who is prompted to sign-in with Authenticator will see number match after February 27th, 2023. If the user is prompted for another method, they won't see any change. +Regardless of their default method, any user who is prompted to sign-in with Authenticator push notifications will see number match after February 27th, 2023. If the user is prompted for another method, they won't see any change. ### Will users who don't use number matching be able to perform MFA? -It depends on how the **Enable and Target** tab is configured. The scope for number match approvals will change under the **Configure** tab to include everyone, but it only applies for users and groups targeted on the **Enable and Target** tab for Push or Any. However, if Target on the **Enable and Target** tab is set to specific groups for Push or Any, and the user isn't a member of those groups, then they won't receive the number matching approvals once the change is implemented on February 27th, 2023 because they aren't a member of the groups defined on the **Enable and Target** tab for Push and/or Any. +It depends on how the **Enable and Target** tab is configured. The scope for number match approvals will change under the **Configure** tab to include everyone, but it only applies for users and groups targeted on the **Enable and Target** tab for Push or Any. However, if Target on the **Enable and Target** tab is set to specific groups for Push or Any, and the user isn't a member of those groups, then they won't receive the number matching approvals once the change is implemented after February 27th, 2023 because they aren't a member of the groups defined on the **Enable and Target** tab for Push and/or Any. ++### Is number matching supported with MFA Server? ++No, number matching isn't enforced because it's not a supported feature for MFA Server, which is [deprecated](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-change-announcements-september-2022-train/ba-p/2967454). ### What happens if a user runs an older version of Microsoft Authenticator? If a user is running an older version of Microsoft Authenticator that doesn't su Older versions of Microsoft Authenticator prompt users to tap and select a number instead of entering the number in their Microsoft Authenticator app. These authentications won't fail, but we highly recommend that users update to the latest version of the app to be able to enter the number. - ## Next steps [Authentication methods in Azure Active Directory](concept-authentication-authenticator-app.md) |
active-directory | Howto Sspr Customization | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/authentication/howto-sspr-customization.md | If your organization doesn't want to notify administrators about password reset ## Customize the sign-in page and access panel -You can customize the sign-in page, such as to add a logo that appears along with the image that fits your company branding. For more information on how to configure company branding, see [Add company branding to your sign-in page in Azure AD](../fundamentals/customize-branding.md). +You can customize the sign-in page, such as to add a logo that appears along with the image that fits your company branding. For more information on how to configure company branding, see [Add company branding to your sign-in page in Azure AD](../fundamentals/how-to-customize-branding.md). The graphics you choose are shown in the following circumstances: |
active-directory | Howto Create Service Principal Portal | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/develop/howto-create-service-principal-portal.md | Title: Create an Azure AD app and service principal in the portal description: Create a new Azure Active Directory app and service principal to manage access to resources with role-based access control in Azure Resource Manager. -+ Previously updated : 10/11/2022 Last updated : 02/01/2023 -# Use the portal to create an Azure AD application and service principal that can access resources +# Create an Azure Active Directory application and service principal that can access resources -This article shows you how to create a new Azure Active Directory (Azure AD) application and service principal that can be used with the role-based access control. When you have applications, hosted services, or automated tools that need to access or modify resources, you can create an identity for the app. This identity is known as a service principal. Access to resources is restricted by the roles assigned to the service principal, giving you control over which resources can be accessed and at which level. For security reasons, it's always recommended to use service principals with automated tools rather than allowing them to log in with a user identity. +In this article, you'll learn how to create an Azure Active Directory (Azure AD) application and service principal that can be used with the role-based access control. When you register a new application in Azure AD, a service principal is automatically created for the app registration. The service principal is the app's identity in the Azure AD tenant. Access to resources is restricted by the roles assigned to the service principal, giving you control over which resources can be accessed and at which level. For security reasons, it's always recommended to use service principals with automated tools rather than allowing them to sign in with a user identity. -This article shows you how to use the portal to create the service principal in the Azure portal. It focuses on a single-tenant application where the application is intended to run within only one organization. You typically use single-tenant applications for line-of-business applications that run within your organization. You can also [use Azure PowerShell](howto-authenticate-service-principal-powershell.md) or the [Azure CLI](/cli/azure/create-an-azure-service-principal-azure-cli) to create a service principal. +In this article, you'll create a single tenant application in the Azure portal. This example is applicable for line-of-business applications used within one organization. You can also [use Azure PowerShell](howto-authenticate-service-principal-powershell.md) or the [Azure CLI](/cli/azure/create-an-azure-service-principal-azure-cli) to create a service principal. > [!IMPORTANT] > Instead of creating a service principal, consider using managed identities for Azure resources for your application identity. If your code runs on a service that supports managed identities and accesses resources that support Azure AD authentication, managed identities are a better option for you. To learn more about managed identities for Azure resources, including which services currently support it, see [What is managed identities for Azure resources?](../managed-identities-azure-resources/overview.md). -## App registration, app objects, and service principals +For more information on the relationship between app registration, application objects, and service principals, read [Application and service principal objects in Azure Active Directory](app-objects-and-service-principals.md). -There is no way to directly create a service principal using the Azure portal. When you register an application through the Azure portal, an application object and service principal are automatically created in your home directory or tenant. For more information on the relationship between app registration, application objects, and service principals, read [Application and service principal objects in Azure Active Directory](app-objects-and-service-principals.md). +## Prerequisites -## Permissions required for registering an app --You must have sufficient permissions to register an application with your Azure AD tenant, and assign to the application a role in your Azure subscription. --### Check Azure AD permissions --1. Select **Azure Active Directory**. -1. Find your role under **Overview**->**My feed**. If you have the **User** role, you must make sure that non-administrators can register applications. -- :::image type="content" source="media/howto-create-service-principal-portal/view-user-info.png" alt-text="Screenshot showing how to find your role."::: --1. In the left pane, select **Users** and then **User settings**. -1. Check the **App registrations** setting. This value can only be set by an administrator. If set to **Yes**, any user in the Azure AD tenant can register an app. --If the app registrations setting is set to **No**, only users with an administrator role may register these types of applications. See [Azure AD built-in roles](../roles/permissions-reference.md#all-roles) to learn about available administrator roles and the specific permissions in Azure AD that are given to each role. If your account is assigned the User role, but the app registration setting is limited to admin users, ask your administrator to either assign you one of the administrator roles that can create and manage all aspects of app registrations, or to enable users to register apps. --### Check Azure subscription permissions --In your Azure subscription, your account must have `Microsoft.Authorization/*/Write` access to assign a role to an AD app. This action is granted through the [Owner](../../role-based-access-control/built-in-roles.md#owner) role or [User Access Administrator](../../role-based-access-control/built-in-roles.md#user-access-administrator) role. If your account is assigned the **Contributor** role, you don't have adequate permission. You will receive an error when attempting to assign the service principal a role. --To check your subscription permissions: +To register an application in your Azure AD tenant, you need: -1. Search for and select **Subscriptions**, or select **Subscriptions** on the **Home** page. +- An Azure AD user account. If you don't already have one, you can [create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). - :::image type="content" source="media/howto-create-service-principal-portal/select-subscription.png" alt-text="Screenshot how to search subscription permissions."::: --1. Select the subscription you want to create the service principal in. -- :::image type="content" source="media/howto-create-service-principal-portal/select-one-subscription.png" alt-text="Select subscription for assignment."::: -- If you don't see the subscription you're looking for, select **global subscriptions filter**. Make sure the subscription you want is selected for the portal. --1. Select **My permissions**. Then, select **Click here to view complete access details for this subscription**. -- :::image type="content" source="media/howto-create-service-principal-portal/view-details.png" alt-text="Select the subscription you want to create the service principal in."::: --1. Select **Role assignments** to view your assigned roles, and determine if you have adequate permissions to assign a role to an AD app. If not, ask your subscription administrator to add you to User Access Administrator role. In the following image, the user is assigned the Owner role, which means that user has adequate permissions. +## Permissions required for registering an app - :::image type="content" source="media/howto-create-service-principal-portal/view-user-role.png" alt-text="Screenshot showing the user is assigned the Owner role."::: +You must have sufficient permissions to register an application with your Azure AD tenant, and assign to the application a role in your Azure subscription. To complete these tasks, you require `Application.ReadWrite.All`permission. ## Register an application with Azure AD and create a service principal -Let's jump straight into creating the identity. If you run into a problem, check the [required permissions](#permissions-required-for-registering-an-app) to make sure your account can create the identity. --1. Sign in to your Azure Account through the <a href="https://portal.azure.com/" target="_blank">Azure portal</a>. -1. Select **Azure Active Directory**. -1. Select **App registrations**. -1. Select **New registration**. -1. Name the application, for example "example-app". Select a supported account type, which determines who can use the application. Under **Redirect URI**, select **Web** for the type of application you want to create. Enter the URI where the access token is sent to. You can't create credentials for a [Native application](../app-proxy/application-proxy-configure-native-client-application.md). You can't use that type for an automated application. After setting the values, select **Register**. +1. Sign-in to the [Azure portal](https://portal.azure.com). +1. Search for and Select **Azure Active Directory**. +1. Select **App registrations**, then select **New registration**. +1. Name the application, for example "example-app". +1. Select a supported account type, which determines who can use the application. +1. Under **Redirect URI**, select **Web** for the type of application you want to create. Enter the URI where the access token is sent to. +1. Select **Register**. :::image type="content" source="media/howto-create-service-principal-portal/create-app.png" alt-text="Type a name for your application."::: You've created your Azure AD application and service principal. -> [!NOTE] -> You can register multiple applications with the same name in Azure AD, but the applications must have different Application (client) IDs. - ## Assign a role to the application To access resources in your subscription, you must assign a role to the application. Decide which role offers the right permissions for the application. To learn about the available roles, see [Azure built-in roles](../../role-based-access-control/built-in-roles.md). -You can set the scope at the level of the subscription, resource group, or resource. Permissions are inherited to lower levels of scope. For example, adding an application to the *Reader* role for a resource group means it can read the resource group and any resources it contains. --1. In the Azure portal, select the level of scope you wish to assign the application to. For example, to assign a role at the subscription scope, search for and select **Subscriptions**, or select **Subscriptions** on the **Home** page. -- :::image type="content" source="media/howto-create-service-principal-portal/select-subscription.png" alt-text="For example, assign a role at the subscription scope."::: --1. Select the particular subscription to assign the application to. -- :::image type="content" source="media/howto-create-service-principal-portal/select-one-subscription.png" alt-text="Select subscription for assignment."::: -- If you don't see the subscription you're looking for, select **global subscriptions filter**. Make sure the subscription you want is selected for the portal. +You can set the scope at the level of the subscription, resource group, or resource. Permissions are inherited to lower levels of scope. +1. Sign-in to the [Azure portal](https://portal.azure.com). +1. Select the level of scope you wish to assign the application to. For example, to assign a role at the subscription scope, search for and select **Subscriptions**. If you don't see the subscription you're looking for, select **global subscriptions filter**. Make sure the subscription you want is selected for the tenant. 1. Select **Access control (IAM)**.-1. Select **Add** > **Add role assignment** to open the **Add role assignment** page. -1. In the **Role** tab, select the role you wish to assign to the application in the list. For example, to allow the application to execute actions like **reboot**, **start** and **stop** instances, select the **Contributor** role. Read more about the [available roles](../../role-based-access-control/built-in-roles.md). -- Select the **Next** button to move to the **Members** tab. Select **Assign access to**-> **User, group, or service principal** and then select **Select members**. By default, Azure AD applications aren't displayed in the available options. To find your application, search by name (for example, "example-app") and select it from the returned list. Click the **Select** button. Then click the **Review + assign** button. +1. Select **Add**, then select **Add role assignment**. +1. In the **Role** tab, select the role you wish to assign to the application in the list. For example, to allow the application to execute actions like reboot, start and stop instances, select the **Contributor** role. +1. Select the **Next**. +1. On the **Members** tab. Select **Assign access to**, then select **User, group, or service principal** +1. Select **Select members**. By default, Azure AD applications aren't displayed in the available options. To find your application, Search for it by its name. +1. Select the **Select** button, then select **Review + assign**. :::image type="content" source="media/howto-create-service-principal-portal/add-role-assignment.png" alt-text="Screenshot showing role assignment."::: Your service principal is set up. You can start using it to run your scripts or The next section shows how to get values that are needed when signing in programmatically. -## Get tenant and app ID values for signing in +## Sign in to the application -When programmatically signing in, pass the tenant ID with your authentication request and the application ID. You also need a certificate or an authentication key (described in the following section). To get those values, use the following steps: +When programmatically signing in, pass the tenant ID and the application ID in your authentication request. You also need a certificate or an authentication key. To obtain the directory (tenant) ID and application ID: -1. Select **Azure Active Directory**. +1. Search for select **Azure Active Directory**. 1. From **App registrations** in Azure AD, select your application.-1. Copy the Directory (tenant) ID and store it in your application code. +1. On the app's overview page, copy the Directory (tenant) ID value and store it in your application code. +1. Copy the Application (client) ID value and store it in your application code. - :::image type="content" source="media/howto-create-service-principal-portal/copy-tenant-id.png" alt-text="Copy the directory (tenant ID) and store it in your app code."::: -- The directory (tenant) ID can also be found in the default directory overview page. --1. Copy the **Application ID** and store it in your application code. -- :::image type="content" source="media/howto-create-service-principal-portal/copy-app-id.png" alt-text="Copy the application (client) ID."::: --## Authentication: Two options +## Set up authentication There are two types of authentication available for service principals: password-based authentication (application secret) and certificate-based authentication. *We recommend using a certificate*, but you can also create an application secret. -### Option 1: Upload a certificate +### Option 1 (recommended): Create and upload a self-signed certificate -You can use an existing certificate if you have one. Optionally, you can create a self-signed certificate for *testing purposes only*. To create a self-signed certificate, open PowerShell and run [New-SelfSignedCertificate](/powershell/module/pki/new-selfsignedcertificate) with the following parameters to create the cert in the user certificate store on your computer: +You can use an existing certificate if you've one. Optionally, you can create a self-signed certificate for *testing purposes only*. To create a self-signed certificate, open Windows PowerShell and run [New-SelfSignedCertificate](/powershell/module/pki/new-selfsignedcertificate) with the following parameters to create the certificate in the user certificate store on your computer: ```powershell $cert=New-SelfSignedCertificate -Subject "CN=DaemonConsoleCert" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature $cert=New-SelfSignedCertificate -Subject "CN=DaemonConsoleCert" -CertStoreLocati Export this certificate to a file using the [Manage User Certificate](/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in) MMC snap-in accessible from the Windows Control Panel. -1. Select **Run** from the **Start** menu, and then enter **certmgr.msc**. -- The Certificate Manager tool for the current user appears. -+1. Select **Run** from the **Start** menu, and then enter **certmgr.msc**. The Certificate Manager tool for the current user appears. 1. To view your certificates, under **Certificates - Current User** in the left pane, expand the **Personal** directory.-1. Right-click on the cert you created, select **All tasks->Export**. -1. Follow the Certificate Export wizard. Do not export the private key, and export to a .CER file. +1. Right-click on the certificate you created, select **All tasks->Export**. +1. Follow the Certificate Export wizard. To upload the certificate: -1. Select **Azure Active Directory**. +1. Search for and select **Azure Active Directory**. 1. From **App registrations** in Azure AD, select your application. 1. Select **Certificates & secrets**.-1. Select **Certificates** > **Upload certificate** and select the certificate (an existing certificate or the self-signed certificate you exported). -- :::image type="content" source="media/howto-create-service-principal-portal/upload-cert.png" alt-text="Select Upload certificate and select the one you want to add."::: -+1. Select **Certificates**, then select **Upload certificate** and then select the certificate (an existing certificate or the self-signed certificate you exported). 1. Select **Add**. After registering the certificate with your application in the application registration portal, enable the client application code to use the certificate. After registering the certificate with your application in the application regis If you choose not to use a certificate, you can create a new application secret. -1. Select **Azure Active Directory**. -1. From **App registrations** in Azure AD, select your application. +1. Search for and select **Azure Active Directory**. +1. Select **App registrations** and select your application from the list. 1. Select **Certificates & secrets**.-1. Select **Client secrets -> New client secret**. -1. Provide a description of the secret, and a duration. When done, select **Add**. +1. Select **Client secrets**, and then Select **New client secret**. +1. Provide a description of the secret, and a duration. +1. Select **Add**. - After saving the client secret, the value of the client secret is displayed. Copy this value because you won't be able to retrieve the key later. You will provide the key value with the application ID to sign in as the application. Store the key value where your application can retrieve it. +Once you've saved the client secret, the value of the client secret is displayed. Copy this value because you won't be able to retrieve the key later. You'll provide the key value with the application ID to sign in as the application. Store the key value where your application can retrieve it. - :::image type="content" source="media/howto-create-service-principal-portal/copy-secret.png" alt-text="Copy the secret value because you can't retrieve this later."::: + :::image type="content" source="media/howto-create-service-principal-portal/copy-secret.png" alt-text="Screenshot showing the client secret."::: ## Configure access policies on resources-Keep in mind, you might need to configure additional permissions on resources that your application needs to access. For example, you must also [update a key vault's access policies](../../key-vault/general/security-features.md#privileged-access) to give your application access to keys, secrets, or certificates. -1. In the <a href="https://portal.azure.com/" target="_blank">Azure portal</a>, navigate to your key vault and select **Access policies**. +You might need to configure extra permissions on resources that your application needs to access. For example, you must also [update a key vault's access policies](../../key-vault/general/security-features.md#privileged-access) to give your application access to keys, secrets, or certificates. ++To configure access policies: ++1. Sign-in to the [Azure portal](https://portal.azure.com). +1. Select your key vault and select **Access policies**. 1. Select **Add access policy**, then select the key, secret, and certificate permissions you want to grant your application. Select the service principal you created previously.-1. Select **Add** to add the access policy, then **Save** to commit your changes. +1. Select **Add** to add the access policy. +1. **Save**. +  ## Next steps-* Learn how to use [Azure PowerShell](howto-authenticate-service-principal-powershell.md) or [Azure CLI](/cli/azure/create-an-azure-service-principal-azure-cli) to create a service principal. -* To learn about specifying security policies, see [Azure role-based access control (Azure RBAC)](../../role-based-access-control/role-assignments-portal.md). -* For a list of available actions that can be granted or denied to users, see [Azure Resource Manager Resource Provider operations](../../role-based-access-control/resource-provider-operations.md). -* For information about working with app registrations by using **Microsoft Graph**, see the [Applications](/graph/api/resources/application) API reference. ++- Learn how to use [Azure PowerShell](howto-authenticate-service-principal-powershell.md) or [Azure CLI](/cli/azure/create-an-azure-service-principal-azure-cli) to create a service principal. +- To learn about specifying security policies, see [Azure role-based access control (Azure RBAC)](../../role-based-access-control/role-assignments-portal.md). +- For a list of available actions that can be granted or denied to users, see [Azure Resource Manager Resource Provider operations](../../role-based-access-control/resource-provider-operations.md). +- For information about working with app registrations by using **Microsoft Graph**, see the [Applications](/graph/api/resources/application) API reference. |
active-directory | Permissions Consent Overview | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/develop/permissions-consent-overview.md | As an application developer, you must identify how your application will access In this access scenario, a user has signed into a client application. The client application accesses the resource on behalf of the user. Delegated access requires delegated permissions. Both the client and the user must be authorized separately to make the request. For more information about the delegated access scenario, see [delegated access scenario](delegated-access-primer.md). -For the client app, the correct delegated permissions must be granted. Delegated permissions can also be referred to as scopes. Scopes are permissions for a given resource that represent what a client application can access on behalf of the user. For more information about scopes, see [scopes and permissions](v2-permissions-and-consent.md#scopes-and-permissions). +For the client app, the correct delegated permissions must be granted. Delegated permissions can also be referred to as scopes. Scopes are permissions for a given resource that represent what a client application can access on behalf of the user. For more information about scopes, see [scopes and permissions](scopes-oidc.md). For the user, the authorization relies on the privileges that the user has been granted for them to access the resource. For example, the user could be authorized to access directory resources by [Azure Active Directory (Azure AD) role-based access control (RBAC)](../roles/custom-overview.md) or to access mail and calendar resources by Exchange Online RBAC. For more information on RBAC for applications, see [RBAC for applications](custom-rbac-for-developers.md). |
active-directory | Whats New Docs | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/develop/whats-new-docs.md | +## January 2023 ++### New articles ++- [Customize claims issued in the JSON web token (JWT) for enterprise applications](active-directory-jwt-claims-customization.md) ++### Updated articles ++- [Access Azure AD protected resources from an app in Google Cloud](workload-identity-federation-create-trust-gcp.md) +- [Configure SAML app multi-instancing for an application in Azure Active Directory](reference-app-multi-instancing.md) +- [Customize browsers and WebViews for iOS/macOS](customize-webviews.md) +- [Customize claims issued in the SAML token for enterprise applications](active-directory-saml-claims-customization.md) +- [Enable cross-app SSO on Android using MSAL](msal-android-single-sign-on.md) +- [Using redirect URIs with the Microsoft Authentication Library (MSAL) for iOS and macOS](redirect-uris-ios.md) + ## December 2022 ### New articles Welcome to what's new in the Microsoft identity platform documentation. This art - [Shared device mode for iOS devices](msal-ios-shared-devices.md) - [Troubleshoot publisher verification](troubleshoot-publisher-verification.md) - [Tutorial: Use shared-device mode in your Android application](tutorial-v2-shared-device-mode.md)--## October 2022 --### Updated articles --- [Access Azure AD protected resources from an app in Google Cloud](workload-identity-federation-create-trust-gcp.md)-- [Configure an app to trust an external identity provider](workload-identity-federation-create-trust.md)-- [Configure a user-assigned managed identity to trust an external identity provider (preview)](workload-identity-federation-create-trust-user-assigned-managed-identity.md)-- [Configuration requirements and troubleshooting tips for Xamarin Android with MSAL.NET](msal-net-xamarin-android-considerations.md)-- [Customize claims emitted in tokens for a specific app in a tenant](active-directory-claims-mapping.md)-- [Desktop app that calls web APIs: Acquire a token using Device Code flow](scenario-desktop-acquire-token-device-code-flow.md)-- [Desktop app that calls web APIs: Acquire a token using integrated Windows authentication](scenario-desktop-acquire-token-integrated-windows-authentication.md)-- [Desktop app that calls web APIs: Acquire a token using Username and Password](scenario-desktop-acquire-token-username-password.md)-- [Making your application multi-tenant](howto-convert-app-to-be-multi-tenant.md)-- [Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow](v2-oauth2-on-behalf-of-flow.md)-- [Prompt behavior with MSAL.js](msal-js-prompt-behavior.md)-- [Quickstart: Register an application with the Microsoft identity platform](quickstart-register-app.md)-- [Tutorial: Sign in users and call the Microsoft Graph API from a JavaScript single-page application](tutorial-v2-javascript-spa.md)-- [Tutorial: Sign in users and call the Microsoft Graph API from a React single-page app (SPA) using auth code flow](tutorial-v2-react.md) |
active-directory | Whats New Docs | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/external-identities/whats-new-docs.md | +## January 2023 ++### Updated articles ++- [Federation with SAML/WS-Fed identity providers for guest users](direct-federation.md) +- [Add a self-service sign-up user flow to an app](self-service-sign-up-user-flow.md) +- [Add a custom approval workflow to self-service sign-up](self-service-sign-up-add-approvals.md) +- [Add Facebook as an identity provider for External Identities](facebook-federation.md) +- [Leave an organization as an external user](leave-the-organization.md) +- [External Identities in Azure Active Directory](external-identities-overview.md) +- [External Identities documentation](index.yml) + ## December 2022 ### Updated articles Welcome to what's new in Azure Active Directory External Identities documentatio - [B2B collaboration overview](what-is-b2b.md) - [Azure Active Directory External Identities: What's new](whats-new-docs.md) - [Tutorial: Enforce multi-factor authentication for B2B guest users](b2b-tutorial-require-mfa.md)--## October 2022 --### Updated articles --- [Tutorial: Bulk invite Azure AD B2B collaboration users](tutorial-bulk-invite.md)-- [Quickstart: Add a guest user and send an invitation](b2b-quickstart-add-guest-users-portal.md)-- [Define custom attributes for user flows](user-flow-add-custom-attributes.md)-- [Create dynamic groups in Azure Active Directory B2B collaboration](use-dynamic-groups.md)-- [Properties of an Azure Active Directory B2B collaboration user](user-properties.md)-- [Authentication and Conditional Access for External Identities](authentication-conditional-access.md)-- [Leave an organization as an external user](leave-the-organization.md)-- [Azure Active Directory External Identities: What's new](whats-new-docs.md)-- [Federation with SAML/WS-Fed identity providers for guest users](direct-federation.md)-- [Example: Configure SAML/WS-Fed based identity provider federation with AD FS](direct-federation-adfs.md)-- [The elements of the B2B collaboration invitation email - Azure Active Directory](invitation-email-elements.md)-- [Configure Microsoft cloud settings for B2B collaboration (Preview)](cross-cloud-settings.md)-- [Add Microsoft account (MSA) as an identity provider for External Identities](microsoft-account.md)-- [How users in your organization can invite guest users to an app](add-users-information-worker.md)- |
active-directory | 4 Secure Access Groups | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/fundamentals/4-secure-access-groups.md | -# Securing external access with groups +# Secure external access with groups in Azure Active Directory and Microsoft 365 -Groups are an essential part of any access control strategy. Azure Active Directory (Azure AD) security groups and Microsoft 365 Groups can be used as the basis for securing access to resources. --Groups are the best option to use as the basis for the following access control mechanisms: +Groups are part of an access control strategy. You can use Azure Active Directory (Azure AD) security groups and Microsoft 365 Groups as the basis for securing access to resources. Use groups for the following access-control mechanisms: * Conditional Access policies--* Entitlement Management Access Packages -+ * [What is Conditional Access?](../conditional-access/overview.md) +* Entitlement management access packages + * [What is entitlement management?](../governance/entitlement-management-overview.md) * Access to Microsoft 365 resources, Microsoft Teams, and SharePoint sites Groups have the following roles: -* Owners ΓÇô Group owners manage the group settings and its membership. --* Members ΓÇô Members who inherit the permissions and access assigned to the group. --* Guests ΓÇô Guests are members from outside of your organization. --## Determine your group strategy --As you develop your group strategy to secure external access to your resources, consider [your desired security posture](1-secure-access-posture.md) to determine the following choices. +* **Group owners** ΓÇô manage group settings and its membership +* **Members** ΓÇô inherit permissions and access assigned to the group +* **Guests** ΓÇô are members outside your organization -* **Who should be able to create groups?** Do you want only administrators to create groups, or do you want employees and or external users to also create these groups. +## Group strategy - * *By default any tenant member can create Azure AD security groups*. +To develop a group strategy to secure external access to your resources, consider the security posture that you want. - * You can [restrict access to the portal for non-administrators](../develop/howto-restrict-your-app-to-a-set-of-users.md) and disable group creation ability in [PowerShell.](../enterprise-users/groups-troubleshooting.md) +Learn more: [Determine your security posture for external access](1-secure-access-posture.md) - * You can also [set up self-service group management in Azure Active Directory](../enterprise-users/groups-self-service-management.md). +### Group creation - * *By default all users can create Microsoft 365 Groups and groups are open for all (internal and external) users in your tenant to join*. +Determine who is granted permissions to create groups: Administrators, employees, and/or external users. Consider the following scenarios: - * [You can restrict Microsoft 365 Group creation](/microsoft-365/solutions/manage-creation-of-groups) to the members of a particular security group. Use Windows PowerShell to configure this setting. +* Tenant members can create Azure AD security groups +* Internal and external users can join groups in your tenant +* Users can create Microsoft 365 Groups +* [Manage who can create Microsoft 365 Groups](/microsoft-365/solutions/manage-creation-of-groups?view=o365-worldwide&preserve-view=true) + * Use Windows PowerShell to configure this setting +* [Restrict your Azure AD app to a set of users in an Azure AD tenant](../develop/howto-restrict-your-app-to-a-set-of-users.md) +* [Set up self-service group management in Azure Active Directory](../enterprise-users/groups-self-service-management.md) +* [Troubleshoot and resolve groups issues](../enterprise-users/groups-troubleshooting.md) -* **Who should be able to invite people to groups?** Can all group members be able to add other members, or can only group owners add members? +### Invitations to groups -* **Who can be invited to groups?** By default, external users can be added to groups. +As part of the group strategy, consider who can invite people, or add them, to groups. Group members can add other members, or group owners can add members. Decide who can be invited. By default, external users can be added to groups. ### Assign users to groups -Users can be assigned to groups both manually based on the user attributes in their user object, or on other criteria. Users can only be assigned to groups dynamically based on their attributes. --For example, you can assign users to groups based on their: --* specific job title or department --* partner organization to which they belong (manually, or through Connected organizations) --* user type (Member or Guest) --* participation in a specific project (manually) --* location --Dynamic groups can contain either users or devices, but not both. You add queries based on user attributes to assign users into the dynamic group. The below example shows queries that add users to the group if they are members (not guests) and in the finance department. +Users are assigned to groups manually, based on user attributes in their user object, or users are assigned based on other criteria. Users are assigned to groups dynamically based on their attributes. For example, you can assign users to groups based on: - +* Job title or department +* Partner organization to which they belong + * Manually, or through connected organizations +* Member or guest user type +* Participation in a project + * Manually +* Location -For more information on dynamic groups, see [Create or update a dynamic group in Azure Active Directory.](../enterprise-users/groups-create-rule.md) +Dynamic groups have users or devices, but not both. To assign users to the dynamic group, add queries based on user attributes. The following screenshot has queries that add users to the group if they are finance department members. -### Do not use groups for multiple purposes +  -When using groups for security or resource access purposes, it's important that they have a single function. If a group is used to grant access to resources, it shouldn't be used for any other purpose. If a group is used for generic purposes such as to define location or team membership, it shouldn't also be used to secure access. +Learn more: [Create or update a dynamic group in Azure AD](../enterprise-users/groups-create-rule.md) -We recommend a naming convention for security groups that makes the purpose clear. For example: +### Use groups for one function -* *Secure_access_finance_apps* +When using groups, it's important they have a single function. If a group is used to grant access to resources, don't use it for another purpose. We recommend a security-group naming convention that makes the purpose clear: -* *Team_membership_finance_team* +* Secure_access_finance_apps +* Team_membership_finance_team +* Location_finance_building -* *Location_finance_building* +### Group types +You can create Azure AD security groups and Microsoft 365 Groups in the Azure portal or the Microsoft 365 Admin portal. Use either group type for securing external access. --### Types of groups --Both Azure AD security groups and Microsoft 365 groups can be created from the Azure AD portal or the Microsoft 365 admin portal. Both types can be used as the basis for securing external access: --| Considerations | Azure AD security groups (manual and dynamic)| Microsoft 365 Groups | +| Considerations |Manual and dynamic Azure AD security groups| Microsoft 365 Groups | | - | - | - |-| What can the group contain?| Users<br>Groups<br>Service principals<br>Devices| Users only | -| Where is the group created?| Azure AD portal<br>Microsoft 365 portal (if to be mail enabled)<br>PowerShell<br>Microsoft Graph<br>End user portal| Microsoft 365 portal<br>Azure AD portal<br>PowerShell<br>Microsoft Graph<br>In Microsoft 365 applications | -| Who creates by default?| Administrators <br>Users| Administrators<br>Users | -| Who can be added by default?| Internal users (tenant members) and guest users | Tenant members and guests from any organization | -| What does it grant access to?| Only resources to which it's assigned.| All group-related resources:<br>(Group mailbox, site, team, chats, and other included Microsoft 365 resources)<br>Any other resources to which group is added | -| Can be used with| Conditional Access<br>Entitlement Management<br>Group licensing| Conditional Access<br>Entitlement Management<br>Sensitivity labels | -+| The group contains| Users<br>Groups<br>Service principals<br>Devices| Users only | +| Where the group is created| Azure AD portal<br>Microsoft 365 portal, if mail-enabled)<br>PowerShell<br>Microsoft Graph<br>End user portal| Microsoft 365 portal<br>Azure AD portal<br>PowerShell<br>Microsoft Graph<br>In Microsoft 365 applications | +| Who creates, by default| Administrators <br>Users| Administrators<br>Users | +| Who is added, by default| Internal users (tenant members) and guest users | Tenant members and guests from an organization | +| Access is granted to| Resources to which it's assigned.| Group-related resources:<br>(Group mailbox, site, team, chats, and other Microsoft 365 resources)<br>Other resources to which group is added | +| Can be used with| Conditional Access<br>entitlement management<br>group licensing| Conditional Access<br>entitlement management<br>sensitivity labels | --Use Microsoft 365 groups to create and manage a set of Microsoft 365 resources, such as a Team and its associated sites and content. TheyΓÇÖre a great choice for a project-based effort. -- +> [!NOTE] +> Use Microsoft 365 Groups to create and manage a set of Microsoft 365 resources, such as a Team and its associated sites and content. ## Azure AD security groups -[Azure AD security groups](./active-directory-manage-groups.md) can contain users or devices and can be used to manage access to +Azure AD security groups can have users or devices. Use these groups to manage access to: -* Azure resources such as Microsoft 365 apps, custom apps, and Software as a Service (SaaS) apps such as ServiceNow of Dropbox. +* Azure resources + * Microsoft 365 apps + * Custom apps + * Software as a Service (SaaS) apps such as Dropbox ServiceNow +* Azure data and subscriptions +* Azure services -* Azure data and subscriptions. +Use Azure AD security groups to assign: -* Azure services. +* Licenses for services + * Microsoft 365 + * Dynamics 365 + * Enterprise mobility and security + * See, [What is group-based licensing in Azure Active Directory?](./active-directory-licensing-whatis-azure-portal.md) +* Elevated permissions + * See, [Use Azure AD groups to manage role assignments](../roles/groups-concept.md) -Azure AD security groups can also be used to: +Learn more: -* assign licenses for services such as Microsoft 365, Dynamics 365, and Enterprise Mobility and Security. For more information, see [group-based licensing](./active-directory-licensing-whatis-azure-portal.md). --* assign elevated permissions. For more information, see [Use Azure AD groups to manage role assignments](../roles/groups-concept.md). --To create a group [in the Azure portal](./active-directory-groups-create-azure-portal.md) navigate to Azure Active Directory, then to Groups. You can also create Azure AD security groups by using [PowerShell cmdlets](../enterprise-users/groups-settings-v2-cmdlets.md). +* [Manage Azure AD groups and group membership](how-to-manage-groups.md) +* [Azure AD version 2 cmdlets for group management](../enterprise-users/groups-settings-v2-cmdlets.md). > [!NOTE]-> A security group can be used for assignment of up to 1500 applications, but not more. +> Use security groups to assign up to 1,500 applications. - +  -> [!IMPORTANT] -> **To create a mail-enabled security group, go to the [Microsoft 365 Admin center](https://admin.microsoft.com/)**. You cannot create it in the Azure AD portal. -<br>You must enable a security group for mail at the time of creation. You canΓÇÖt enable it later. +### Mail-enabled security group ++To create a mail-enabled security group, go to the [Microsoft 365 admin center](https://admin.microsoft.com/). Enable a security group for mail during creation. You canΓÇÖt enable it later. You can't create the group in the Azure AD portal. ### Hybrid organizations and Azure AD security groups -Hybrid organizations have both an on-premises infrastructure and an Azure AD cloud infrastructure. Many hybrid organizations that use Active Directory create their security groups on-premises and sync them to the cloud. By using this method, only users in the on-premises environment can be added to the security groups. +Hybrid organizations have infrastructure for on-premises and an Azure AD. Hybrid organizations that use Active Directory can create security groups on-premises and sync them to the cloud. Therefore, only users in the on-premises environment can be added to the security groups. -**Protect your on-premises infrastructure from compromise, as a breach on-premises can be used to gain access to your Microsoft 365 tenant**. See [Protecting Microsoft 365 from on-premises attacks](./protect-m365-from-on-premises-attacks.md) for guidance. +> [!IMPORTANT] +> Protect your on-premises infrastructure from compromise. See, [Protecting Microsoft 365 from on-premises attacks](./protect-m365-from-on-premises-attacks.md). ## Microsoft 365 Groups -[Microsoft 365 Groups](/microsoft-365/admin/create-groups/office-365-groups) are the foundational membership service that drives all access across Microsoft 365. They can be created from the [Azure portal](https://portal.azure.com/), or the [Microsoft 365 portal](https://admin.microsoft.com/). When a Microsoft 365 group is created, you grant access to a group of resources used to collaborate. See [Overview of Microsoft 365 Groups for administrators](/microsoft-365/admin/create-groups/office-365-groups) for a complete listing of these resources. --Microsoft 365 Groups have the following nuances for their roles: +Microsoft 365 Groups is the membership service for access across Microsoft 365. They can be created from the Azure portal, or the Microsoft 365 portal. When you create a Microsoft 365 Group, you grant access to a group of resources for collaboration. -* **Owners** - Group owners can add or remove members and have unique administrative permissions in the group, such as the ability to delete conversations from the shared inbox or change group settings. Group owners can rename the group, update the description or picture and more. +Learn more: -* **Members** - Group members can access everything in the group but can't change group settings. By default, group members can invite guests to join your group. You can [control that setting](/microsoft-365/admin/create-groups/manage-guest-access-in-groups). +* [Overview of Microsoft 365 Groups for administrators](/microsoft-365/admin/create-groups/office-365-groups?view=o365-worldwide&preserve-view=true) +* [Create a group in the Microsoft 365 admin center](/microsoft-365/admin/create-groups/create-groups?view=o365-worldwide&preserve-view=true) +* [Azure portal](https://portal.azure.com/) +* [Microsoft 365 portal](https://admin.microsoft.com/) -* **Guests** - Group guests are members who are from outside your organization. Guests by default have some limits to functionality in Teams. +### Microsoft 365 Groups roles - +* **Group owners** + * Add or remove members + * Delete conversations from the shared inbox + * Change group settings + * Rename the group + * Update the description or picture +* **Members** + * Access everything in the group + * Can't change group settings + * Can invite guests to join the group + * [Manage guest access in Microsoft 365 groups](/microsoft-365/admin/create-groups/manage-guest-access-in-groups) +* **Guests** + * Are members from outside your organization. + * Have some limits to functionality in Teams ### Microsoft 365 Group settings -You select email alias, privacy, and whether to enable the group for teams at the time of set-up. +Select email alias, privacy, and whether to enable the group for teams. - +  -After setup, you add members, and configure settings for email usage, etc. +After setup, add members, and configure settings for email usage, etc. ### Next steps -See the following articles on securing external access to resources. We recommend you take the actions in the listed order. +See the following articles to learn more about securing external access to resources. We recommend you follow the listed order. -1. [Determine your desired security posture for external access](1-secure-access-posture.md) +1. [Determine your security posture for external access](1-secure-access-posture.md) -2. [Discover your current state](2-secure-access-current-state.md) +2. [Discover the current state of external collaboration in your organization](2-secure-access-current-state.md) -3. [Create a governance plan](3-secure-access-plan.md) +3. [Create a security plan for external access](3-secure-access-plan.md) -4. [Use groups for security](4-secure-access-groups.md) (You are here.) +4. [Secure external access with groups in Azure AD and Microsoft 365](4-secure-access-groups.md) (You're here) -5. [Transition to Azure AD B2B](5-secure-access-b2b.md) +5. [Transition to governed collaboration with Azure AD B2B collaboration](5-secure-access-b2b.md) -6. [Secure access with Entitlement Management](6-secure-access-entitlement-managment.md) +6. [Manage external access with Azure AD entitlement management](6-secure-access-entitlement-managment.md) -7. [Secure access with Conditional Access policies](7-secure-access-conditional-access.md) +7. [Manage external access with Conditional Access policies](7-secure-access-conditional-access.md) -8. [Secure access with Sensitivity labels](8-secure-access-sensitivity-labels.md) +8. [Control access with sensitivity labels](8-secure-access-sensitivity-labels.md) -9. [Secure access to Microsoft Teams, OneDrive, and SharePoint](9-secure-access-teams-sharepoint.md) +9. [Secure external access to Microsoft Teams, SharePoint, and OneDrive for Business](9-secure-access-teams-sharepoint.md) |
active-directory | 8 Secure Access Sensitivity Labels | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/fundamentals/8-secure-access-sensitivity-labels.md | Title: Control external access to resources in Azure Active Directory with sensitivity labels. -description: Use sensitivity labels as a part of your overall security plan for external access. + Title: Control external access to resources in Azure Active Directory with sensitivity labels +description: Use sensitivity labels as a part of your overall security plan for external access -# Control access with sensitivity labels +# Control external access to resources in Azure Active Directory with sensitivity labels -[Sensitivity labels](/microsoft-365/compliance/sensitivity-labels) help you control access to your content in Office 365 applications, and in containers like Microsoft Teams, Microsoft 365 Groups, and SharePoint sites. They can protect your content without hindering your usersΓÇÖ collaboration and production abilities. Sensitivity labels allow you to send your organizationΓÇÖs content across devices, apps, and services, while protecting your data and meeting your compliance and security policies. --With sensitivity labels you can: --* **Classify content without adding any protection settings**. You can assign a classification to content (like a sticker) that persists and roams with your content as itΓÇÖs used and shared. You can use this classification to generate usage reports and see activity data for your sensitive content. --* **Enforce protection settings such as encryption, watermarks, and access restrictions**. For example, users can apply a Confidential label to a document or email, and that label can [encrypt the content](/microsoft-365/compliance/encryption-sensitivity-labels) and add a ΓÇ£ConfidentialΓÇ¥ watermark. In addition, you can [apply a sensitivity label to a container](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites) like a SharePoint site, and enforce whether external users can access the content it contains. --Sensitivity labels on email and other content travel with the content. Sensitivity labels on containers can restrict access to the container, but content in the container doesn't inherit the label. For example, a user could take content from a protected site, download it, and then share it without restrictions unless the content also had a sensitivity label. -- >[!NOTE] ->To apply sensitivity labels users must be signed into their Microsoft work or school account. --## Permissions necessary to create and manage sensitivity levels --Members of your compliance team who will create sensitivity labels need permissions to the Microsoft 365 Defender portal, Microsoft Purview compliance portal, or Office 365 Security & Compliance Center. --By default, global administrators for your tenant have access to these admin centers and can give compliance officers and other people access, without giving them all the permissions of a tenant admin. For this delegated limited admin access, add users to the Compliance Data Administrator, Compliance Administrator, or Security Administrator role group. --## Determine your sensitivity label strategy +Use sensitivity labels to help control access to your content in Office 365 applications, and in containers like Microsoft Teams, Microsoft 365 Groups, and SharePoint sites. They protect content without hindering user collaboration. Use sensitivity labels to send organization-wide content across devices, apps, and services, while protecting data. Sensitivity labels help organizations meet compliance and security policies. + +See, [Learn about sensitivity labels](/microsoft-365/compliance/sensitivity-labels?view=o365-worldwide&preserve-view=true) -As you think about governing external access to your content, determine the following: +## Assign classification and enforce protection settings -**For all content and containers** +You can classify content without adding any protection settings. Content classification assignment stays with the content while itΓÇÖs used and shared. The classification generates usage reports with sensitive-content activity data. -* How will you define what is High, Medium, or Low Business Impact (HBI, MBI, LBI)? Consider the impact to your organization if specific types of content are shared inappropriately. +Enforce protection settings such as encryption, watermarks, and access restrictions. For example, users apply a Confidential label to a document or email. The label can encrypt the content and add a Confidential watermark. In addition, you can apply a sensitivity label to a container like a SharePoint site, and help manage external users access. - * Content with specific types of inherently [sensitive content](/microsoft-365/compliance/apply-sensitivity-label-automatically), such as credit cards or passport numbers +Learn more: - * Content created by specific groups or people (for example, compliance officers, financial officers, or executives) +* [Restrict access to content by using sensitivity labels to apply encryption](/microsoft-365/compliance/encryption-sensitivity-labels?view=o365-worldwide&preserve-view=true) +* [Use sensitivity labels to protect content in Microsoft Teams, Microsoft 365 Groups, and SharePoint sites](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites) - * Content in specific libraries or sites. For example, containers hosting organizational strategy or private financial data +Sensitivity labels on containers can restrict access to the container, but content in the container doesn't inherit the label. For example, a user takes content from a protected site, downloads it, and then shares it without restrictions, unless the content had a sensitivity label. - * Other criteria + >[!NOTE] +>To apply sensitivity labels users sign into their Microsoft work or school account. -* What categories of content (for example HBI content) should be restricted from access by external users? +## Permissions to create and manage sensitivity levels - * Restrictions can include actions like restricting access to containers, and encrypting content. +Team members who need to create sensitivity labels require permissions to: -* What defaults should be in place for HBI data, sites, or Microsoft 365 Groups? +* Microsoft 365 Defender portal, +* Microsoft Purview compliance portal, or +* [Microsoft Purview compliance portal](/microsoft-365/compliance/microsoft-365-compliance-center?view=o365-worldwide&preserve-view=true) -* Where will you use sensitivity labels to [label and monitor](/microsoft-365/compliance/sensitivity-labels), versus to [enforce encryption](/microsoft-365/compliance/encryption-sensitivity-labels) or to [enforce container access restrictions](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites)? +By default, tenant Global Administrators have access to admin centers and can provide access, without granting tenant Admin permissions. For this delegated limited admin access, add users to the following role groups: -**For email and content** +* Compliance Data Administrator, +* Compliance Administrator, or +* Security Administrator -* Do you want to [automatically apply sensitivity labels](/microsoft-365/compliance/apply-sensitivity-label-automatically) to content, or do so manually? +## Sensitivity label strategy - * If you choose to do so manually, do you want to [recommend that users apply a label](/microsoft-365/compliance/apply-sensitivity-label-automatically)? +As you plan the governance of external access to your content, consider content, containers, email, and more. -**For containers** +### High, Medium, or Low Business Impact -* What criteria will determine if M365 Groups, Teams, or SharePoint sites require access to be restricted by using sensitivity labels? +To define High, Medium, or Low Business Impact (HBI, MBI, LBI) for data, sites, and groups, consider the effect on your organization if the wrong content types are shared. -* Do you want to only label content in these containers moving forward, or do you want to [automatically label](/microsoft-365/compliance/apply-sensitivity-label-automatically) existing files in SharePoint and OneDrive? +* Credit card, passport, national-ID numbers + * [Apply a sensitivity label to content automatically](/microsoft-365/compliance/apply-sensitivity-label-automatically?view=o365-worldwide&preserve-view=true) +* Content created by corporate officers: compliance, finance, executive, etc. +* Strategic or financial data in libraries or sites. -See these [common scenarios for sensitivity labels](/microsoft-365/compliance/get-started-with-sensitivity-labels) for other ideas on how you can use sensitivity labels. +Consider the content categories that external users can't have access to, such as containers and encrypted content. You can use sensitivity labels, enforce encryption, or use container access restrictions. -### Sensitivity labels on email and content +### Email and content -When you assign a sensitivity label to a document or email, it's like a stamp that's applied to content that is customizable, clear text, and persistent. +Sensitivity labels can be applied automatically or manually to content. -* **Customizable** means you can create labels appropriate for your organization and determine what happens when they're applied. +See, [Apply a sensitivity label to content automatically](/microsoft-365/compliance/apply-sensitivity-label-automatically?view=o365-worldwide&preserve-view=true) -* **Clear text** means itΓÇÖs a part of the itemΓÇÖs metadata and is readable by applications and services so that they can apply their own protective actions. +#### Sensitivity labels on email and content -* **Persistent** means the label and any associated protections roam with the content, and become the basis for applying and enforcing policies. +A sensitivity label in a document or email is customizable, clear text, and persistent. - +* **Customizable** - create labels for your organization and determine the resulting actions +* **Clear text** - is incorporated in metadata and readable by applications and services +* **Persistency** - ensures the label and associated protections stay with the content, and help enforce policies > [!NOTE]-> Each item of content can have a single sensitivity label applied to it. ---### Sensitivity labels on containers --You can apply sensitivity labels on containers such as [Microsoft 365 Groups](../enterprise-users/groups-assign-sensitivity-labels.md), [Microsoft Teams](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites), and [SharePoint sites](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites). When you apply this sensitivity label to a supported container, the label automatically applies the classification and protection settings to the connected site or group. Sensitivity labels on these containers can control the following aspects of containers: --* **Privacy**. You can choose who can see the site: specific users, all internal users, or anyone. +> Each content item can have one sensitivity label applied. -* **External user access**. Controls whether the group owner can add guests to the group. +### Containers -* **Access from unmanaged devices**. Determines if and how unmanaged devices can access content. -- -- -- +Determine the access criteria if Microsoft 365 Groups, Teams, or SharePoint sites are restricted with sensitivity labels. You can label content in containers or use automatic labeling for files in SharePoint, OneDrive, etc. -When you apply a sensitivity label to a container such as a SharePoint site, it is not applied to content there: sensitivity labels on containers control access to the content within the container. +Learn more: [Get started with sensitivity labels](/microsoft-365/compliance/get-started-with-sensitivity-labels?view=o365-worldwide&preserve-view=true) -* If you want to automatically apply labels to the content within the container, see [Apply a sensitivity to content automatically](/microsoft-365/compliance/apply-sensitivity-label-automatically). +#### Sensitivity labels on containers -* If you want users to be able to manually apply labels to this content, be sure that youΓÇÿve [enabled sensitivity labels for Office files in SharePoint and OneDrive](/microsoft-365/compliance/sensitivity-labels-sharepoint-onedrive-files). +You can apply sensitivity labels to containers such as Microsoft 365 Groups, Microsoft Teams, and SharePoint sites. Sensitivity labels on a supported container apply the classification and protection settings to the connected site or group. Sensitivity labels on these containers can control: -### Plan to implement sensitivity labels +* **Privacy** - select the users who can see the site +* **External user access** - determine if group owners can add guests to a group +* **Access from unmanaged devices** - decide if and how unmanaged devices access content -Once you have determined how you want to use sensitivity labels, and to what content and sites you want to apply them, see the following documentation to help you perform your implementation. +  -1. [Get started with sensitivity labels](/microsoft-365/compliance/get-started-with-sensitivity-labels) +Sensitivity labels applied to a container, such as a SharePoint site, aren't applied to content in the container; they control access to content in the container. Labels can be applied automatically to the content in the container. For users to manually apply labels to content, enable sensitivity labels for Office files in SharePoint and OneDrive. -2. [Create a deployment strategy](/microsoft-365/compliance/get-started-with-sensitivity-labels) +Learn more: -3. [Create and publish sensitivity labels](/microsoft-365/compliance/create-sensitivity-labels) +* [Enable sensitivity labels for Office files in SharePoint and OneDrive](/microsoft-365/compliance/sensitivity-labels-sharepoint-onedrive-files?view=o365-worldwide&preserve-view=true). +* [Use sensitivity labels to protect content in Microsoft Teams, Microsoft 365 Groups, and SharePoint sites](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites) +* [Assign sensitivity labels to Microsoft 365 groups in Azure AD](../enterprise-users/groups-assign-sensitivity-labels.md) -4. [Restrict access to content using sensitivity labels to apply encryption](/microsoft-365/compliance/encryption-sensitivity-labels) +### Implement sensitivity labels -5. [Use sensitivity labels with teams, groups, and sites](/microsoft-365/compliance/sensitivity-labels-teams-groups-sites) +After you determine use of sensitivity labels, see the following documentation for implementation. -6. [Enable sensitivity labels for Office files in SharePoint and OneDrive](/microsoft-365/compliance/sensitivity-labels-sharepoint-onedrive-files) +* [Get started with sensitivity labels](/microsoft-365/compliance/get-started-with-sensitivity-labels?view=o365-worldwide&preserve-view=true) +* [Create and publish sensitivity labels](/microsoft-365/compliance/create-sensitivity-labels?view=o365-worldwide&preserve-view=true) +* [Restrict access to content by using sensitivity labels to apply encryption](/microsoft-365/compliance/encryption-sensitivity-labels?view=o365-worldwide&preserve-view=true) -### Next steps +## Next steps -See the following articles on securing external access to resources. We recommend you take the actions in the listed order. +See the following articles to learn more about securing external access to resources. We recommend you follow the listed order. -1. [Determine your desired security posture for external access](1-secure-access-posture.md) +1. [Determine your security posture for external access](1-secure-access-posture.md) -2. [Discover your current state](2-secure-access-current-state.md) +2. [Discover the current state of external collaboration in your organization](2-secure-access-current-state.md) -3. [Create a governance plan](3-secure-access-plan.md) +3. [Create a security plan for external access](3-secure-access-plan.md) -4. [Use groups for security](4-secure-access-groups.md) +4. [Secure external access with groups in Azure AD and Microsoft 365](4-secure-access-groups.md) -5. [Transition to Azure AD B2B](5-secure-access-b2b.md) +5. [Transition to governed collaboration with Azure AD B2B collaboration](5-secure-access-b2b.md) -6. [Secure access with Entitlement Management](6-secure-access-entitlement-managment.md) +6. [Manage external access with Azure AD entitlement management](6-secure-access-entitlement-managment.md) -7. [Secure access with Conditional Access policies](7-secure-access-conditional-access.md) +7. [Manage external access with Conditional Access policies](7-secure-access-conditional-access.md) -8. [Secure access with Sensitivity labels](8-secure-access-sensitivity-labels.md) (You are here.) +8. [Control external access to resources in Azure AD with sensitivity labels](8-secure-access-sensitivity-labels.md) (You're here) -9. [Secure access to Microsoft Teams, OneDrive, and SharePoint](9-secure-access-teams-sharepoint.md) +9. [Secure external access to Microsoft Teams, SharePoint, and OneDrive for Business](9-secure-access-teams-sharepoint.md) |
active-directory | Whats Deprecated Azure Ad | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/fundamentals/whats-deprecated-azure-ad.md | + + Title: What's deprecated in Azure Active Directory? +description: Learn about features being deprecated in Azure Active Directory ++++++ Last updated : 01/27/2023+++++++# What's deprecated in Azure Active Directory? ++The lifecycle of functionality, features, and services are governed by policy, support timelines, data, also leadership and engineering team decisions. Lifecycle information allows customers to predictably plan long-term deployment aspects, transition from outdated to new technology, and help improve business outcomes. Use the definitions below to understand the following table with change information about Azure Active Directory (Azure AD) features, services, and functionality. ++Get notified about when to revisit this page for updates by copying and pasting this URL: `https://learn.microsoft.com/api/search/rss?search=%22What's+deprecated+in+Azure+Active+Directory%22&locale=en-us` into your  feed reader. ++## Upcoming changes ++Use the following table to learn about changes including deprecations, retirements, breaking changes and rebranding. Also find key dates and recommendations. ++ > [!NOTE] + > Dates and times are United States Pacific Standard Time, and are subject to change. ++|Functionality, feature, or service|Change|New tenant change date |Current tenant change date| +||||| +|[Azure AD Graph API](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-change-announcements-september-2022-train/ba-p/2967454)|Deprecation|Jun 30, 2022|Jun 30, 2022| +|Microsoft Authenticator app [Number matching](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/defend-your-users-from-mfa-fatigue-attacks/ba-p/2365677)|Feature change|Feb 27, 2023|Feb 27, 2023| +|Azure AD DS [virtual network deployments](../../active-directory-domain-services/migrate-from-classic-vnet.md)|Retirement|Mar 1, 2023|Mar 1, 2023| +|[License management API, PowerShell](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/migrate-your-apps-to-access-the-license-managements-apis-from/ba-p/2464366)|Retirement|Nov 1, 2022|Mar 31, 2023| +|[Azure AD Authentication Library (ADAL)](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-change-announcements-september-2022-train/ba-p/2967454)|Retirement|Jun 2023|Jun 2023| +|[Azure AD PowerShell](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-change-announcements-september-2022-train/ba-p/2967454)|Retirement|Jun 30, 2023|Jun 30, 2023| +|[Azure AD MFA Server](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-change-announcements-september-2022-train/ba-p/2967454)|Retirement|Sep 30, 2024|Sep 30, 2024| +++ > [!IMPORTANT] + > Later versions of functionality, features, and services might not meet current security requirements. Microsoft may be unable to provide security updates for older products. ++See the following two sections for definitions of categories, change state, etc. ++## Deprecation, retirement, breaking change, feature change, and rebranding ++Use the definitions in this section help clarify the state, availability, and support of features, services, and functionality. ++|Category|Definition|Communication schedule| +|||| +|Deprecation|The state of a feature, functionality, or service no longer in active development. A deprecated feature might be retired and removed from future releases.|2 times per year: March and September| +|Retirement|Signals retirement in a specified period. Customers canΓÇÖt adopt the service or feature, and engineering investments are reduced. Later, the feature reaches end-of-life and is unavailable to any customer.|2 times per year: March and September| +|Breaking change|A change that might break the customer or partner experience if action isnΓÇÖt taken, or a change made, for continued operation.|4 times per year: March, June, September, and December| +|Feature change|Change to an IDNA feature that requires no customer action, but is noticeable to them. Typically, these changes are in the user interface/user experperience (UI/UX).|4 times per year: March, June, September, and December| +|Rebranding|A new name, term, symbol, design, concept or combination thereof for an established brand to develop a differentiated experience.|As scheduled or announced| ++### Terminology ++* **End-of-life** - engineering investments have ended, and the feature is unavailable to any customer +* **Current tenant change date** - the change date goes into effect for tenants created before the new tenant change date +* **New tenant change date** - the change date goes into effect for tenants created after the change date ++## Next steps +[What's new in Azure Active Directory?](../../active-directory/fundamentals/whats-new.md) ++## Resources +* [Microsoft Entra Change Announcement blog](https://techcommunity.microsoft.com/t5/microsoft-entra-azure-ad-blog/microsoft-entra-change-announcements-november-2022-train/ba-p/2967452) +* Devices: [End-of-life management and recycling](https://www.microsoft.com/legal/compliance/recycling) |
active-directory | Whats New Sovereign Clouds | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/fundamentals/whats-new-sovereign-clouds.md | |
active-directory | Whats New | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/fundamentals/whats-new.md | In Azure AD entitlement management, a new form of access package assignment poli ---## July 2022 - -### Public Preview - ADFS to Azure AD: SAML App Multi-Instancing --**Type:** New feature -**Service category:** Enterprise Apps -**Product capability:** SSO --Users can now configure multiple instances of the same application within an Azure AD tenant. It's now supported for both IdP, and Service Provider (SP), initiated single sign-on requests. Multiple application accounts can now have a separate service principal to handle instance-specific claims mapping and roles assignment. For more information, see: --- [Configure SAML app multi-instancing for an application - Microsoft Entra | Microsoft Docs](../develop/reference-app-multi-instancing.md)-- [Customize app SAML token claims - Microsoft Entra | Microsoft Docs](../develop/active-directory-saml-claims-customization.md)------### Public Preview - ADFS to Azure AD: Apply RegEx Replace to groups claim content --**Type:** New feature -**Service category:** Enterprise Apps -**Product capability:** SSO -- --Administrators up until recently has the capability to transform claims using many transformations, however using regular expression for claims transformation wasn't exposed to customers. With this public preview release, administrators can now configure and use regular expressions for claims transformation using portal UX. -For more information, see:[Customize app SAML token claims - Microsoft Entra | Microsoft Docs](../develop/active-directory-saml-claims-customization.md). - --- ---### Public Preview - Azure AD Domain Services - Trusts for User Forests --**Type:** New feature -**Service category:** Azure AD Domain Services -**Product capability:** Azure AD Domain Services - --You can now create trusts on both user and resource forests. On-premises AD DS users can't authenticate to resources in the Azure AD DS resource forest until you create an outbound trust to your on-premises AD DS. An outbound trust requires network connectivity to your on-premises virtual network on which you have installed Azure AD Domain Service. On a user forest, trusts can be created for on-premises AD forests that aren't synchronized to Azure AD DS. --To learn more about trusts and how to deploy your own, visit [How trust relationships work for forests in Active Directory](../../active-directory-domain-services/concepts-forest-trust.md). - - --- ---### New Federated Apps available in Azure AD Application gallery - July 2022 --**Type:** New feature -**Service category:** Enterprise Apps -**Product capability:** 3rd Party Integration - --In July 2022 we've added the following 28 new applications in our App gallery with Federation support: --[Lunni Ticket Service](https://ticket.lunni.io/login), [TESMA](https://tesma.com/), [Spring Health](https://benefits.springhealth.com/care), [Sorbet](https://lite.sorbetapp.com/login), [Rainmaker UPS](https://upsairlines.rainmaker.aero/rainmaker.security.web/), [Planview ID](../saas-apps/planview-id-tutorial.md), [Karbonalpha](https://saas.karbonalpha.com/settings/api), [Headspace](../saas-apps/headspace-tutorial.md), [SeekOut](../saas-apps/seekout-tutorial.md), [Stackby](../saas-apps/stackby-tutorial.md), [Infrascale Cloud Backup](../saas-apps/infrascale-cloud-backup-tutorial.md), [Keystone](../saas-apps/keystone-tutorial.md), [LMS・教育管理システム Leaf](../saas-apps/lms-and-education-management-system-leaf-tutorial.md), [ZDiscovery](../saas-apps/zdiscovery-tutorial.md), [ラインズeライブラリアドバンス (Lines eLibrary Advance)](../saas-apps/lines-elibrary-advance-tutorial.md), [Rootly](../saas-apps/rootly-tutorial.md), [Articulate 360](../saas-apps/articulate360-tutorial.md), [Rise.com](../saas-apps/risecom-tutorial.md), [SevOne Network Monitoring System (NMS)](../saas-apps/sevone-network-monitoring-system-tutorial.md), [PGM](https://ups-pgm.4gfactor.com/azure/), [TouchRight Software](https://app.touchrightsoftware.com/), [Tendium](../saas-apps/tendium-tutorial.md), [Training Platform](../saas-apps/training-platform-tutorial.md), [Znapio](https://app.znapio.com/), [Preset](../saas-apps/preset-tutorial.md), [itslearning MS Teams sync](https://itslearning.com/global/), [Veza](../saas-apps/veza-tutorial.md), [Trax](https://app.trax.co/authn/login) --You can also find the documentation of all the applications from here https://aka.ms/AppsTutorial, --For listing your application in the Azure AD app gallery, please read the details here https://aka.ms/AzureADAppRequest --- -- ---### General Availability - No more waiting, provision groups on demand into your SaaS applications. --**Type:** New feature -**Service category:** Provisioning -**Product capability:** Identity Lifecycle Management - --Pick a group of up to five members and provision them into your third-party applications in seconds. Get started testing, troubleshooting, and provisioning to non-Microsoft applications such as ServiceNow, ZScaler, and Adobe. For more information, see: [On-demand provisioning in Azure Active Directory](../app-provisioning/provision-on-demand.md). - --- --### General Availability – Protect against by-passing of cloud Azure AD Multi-Factor Authentication when federated with Azure AD --**Type:** New feature -**Service category:** MS Graph -**Product capability:** Identity Security & Protection - --We're delighted to announce a new security protection that prevents bypassing of cloud Azure AD Multi-Factor Authentication when federated with Azure AD. When enabled for a federated domain in your Azure AD tenant, it ensures that a compromised federated account can't bypass Azure AD Multi-Factor Authentication by imitating that a multi factor authentication has already been performed by the identity provider. The protection can be enabled via new security setting, [federatedIdpMfaBehavior](/graph/api/resources/internaldomainfederation?view=graph-rest-beta#federatedidpmfabehavior-values&preserve-view=true). -- -We highly recommend enabling this new protection when using Azure AD Multi-Factor Authentication as your multi factor authentication for your federated users. To learn more about the protection and how to enable it, visit [Enable protection to prevent by-passing of cloud Azure AD Multi-Factor Authentication when federated with Azure AD](/windows-server/identity/ad-fs/deployment/best-practices-securing-ad-fs#enable-protection-to-prevent-by-passing-of-cloud-azure-ad-multi-factor-authentication-when-federated-with-azure-ad). - --- --### Public preview - New provisioning connectors in the Azure AD Application Gallery - July 2022 --**Type:** New feature -**Service category:** App Provisioning -**Product capability:** 3rd Party Integration - --You can now automate creating, updating, and deleting user accounts for these newly integrated apps: --- [Tableau Cloud](../saas-apps/tableau-online-provisioning-tutorial.md)--For more information about how to better secure your organization by using automated user account provisioning, see [Automate user provisioning to SaaS applications with Azure AD](../app-provisioning/user-provisioning.md). - --- --### General Availability - Tenant-based service outage notifications --**Type:** New feature -**Service category:** Other -**Product capability:** Platform - --Azure Service Health supports service outage notifications to Tenant Admins for Azure Active Directory issues. These outages will also appear on the Azure AD Admin Portal Overview page with appropriate links to Azure Service Health. Outage events will be able to be seen by built-in Tenant Administrator Roles. We'll continue to send outage notifications to subscriptions within a tenant for transition. More information is available at: [What are Service Health notifications in Azure Active Directory?](../reports-monitoring/overview-service-health-notifications.md). -- --- ---### Public Preview - Multiple Passwordless Phone sign-in Accounts for iOS devices --**Type:** New feature -**Service category:** Authentications (Logins) -**Product capability:** User Authentication - --End users can now enable passwordless phone sign-in for multiple accounts in the Authenticator App on any supported iOS device. Consultants, students, and others with multiple accounts in Azure AD can add each account to Microsoft Authenticator and use passwordless phone sign-in for all of them from the same iOS device. The Azure AD accounts can be in either the same, or different, tenants. Guest accounts aren't supported for multiple account sign-ins from one device. ---Note that end users are encouraged to enable the optional telemetry setting in the Authenticator App, if not done so already. For more information, see: [Enable passwordless sign-in with Microsoft Authenticator](../authentication/howto-authentication-passwordless-phone.md) -- --- - --### Public Preview - Azure AD Domain Services - Fine Grain Permissions --**Type:** Changed feature -**Service category:** Azure AD Domain Services -**Product capability:** Azure AD Domain Services -- --Previously to set up and administer your AAD-DS instance you needed top level permissions of Azure Contributor and Azure AD Global Administrator. Now for both initial creation, and ongoing administration, you can utilize more fine grain permissions for enhanced security and control. The prerequisites now minimally require: --- You need [Application Administrator](../roles/permissions-reference.md#application-administrator) and [Groups Administrator](../roles/permissions-reference.md#groups-administrator) Azure AD roles in your tenant to enable Azure AD DS.-- You need [Domain Services Contributor](../../role-based-access-control/built-in-roles.md#domain-services-contributor) Azure role to create the required Azure AD DS resources.- --Check out these resources to learn more: --- [Tutorial - Create an Azure Active Directory Domain Services managed domain | Microsoft Docs](../../active-directory-domain-services/tutorial-create-instance.md#prerequisites)-- [Least privileged roles by task - Azure Active Directory | Microsoft Docs](../roles/delegate-by-task.md#domain-services)-- [Azure built-in roles - Azure RBAC | Microsoft Docs](../../role-based-access-control/built-in-roles.md#domain-services-contributor)-- --- --### General Availability- Azure AD Connect update release with new functionality and bug fixes --**Type:** Changed feature -**Service category:** Provisioning -**Product capability:** Identity Lifecycle Management -- --A new Azure AD Connect release fixes several bugs and includes new functionality. This release is also available for auto upgrade for eligible servers. For more information, see: [Azure AD Connect: Version release history](../hybrid/reference-connect-version-history.md#21150). --- --### General Availability - Cross-tenant access settings for B2B collaboration --**Type:** Changed feature -**Service category:** B2B -**Product capability:** B2B/B2C -- --Cross-tenant access settings enable you to control how users in your organization collaborate with members of external Azure AD organizations. Now you’ll have granular inbound and outbound access control settings that work on a per org, user, group, and application basis. These settings also make it possible for you to trust security claims from external Azure AD organizations like multi-factor authentication (MFA), device compliance, and hybrid Azure AD joined devices. For more information, see: [Cross-tenant access with Azure AD External Identities](../external-identities/cross-tenant-access-overview.md). - --- --### General Availability- Expression builder with Application Provisioning --**Type:** Changed feature -**Service category:** Provisioning -**Product capability:** Outbound to SaaS Applications - --Accidental deletion of users in your apps or in your on-premises directory could be disastrous. We’re excited to announce the general availability of the accidental deletions prevention capability. When a provisioning job would cause a spike in deletions, it will first pause and provide you visibility into the potential deletions. You can then accept or reject the deletions and have time to update the job’s scope if necessary. For more information, see [Understand how expression builder in Application Provisioning works](../app-provisioning/expression-builder.md). - --- ---### Public Preview - Improved app discovery view for My Apps portal --**Type:** Changed feature -**Service category:** My Apps -**Product capability:** End User Experiences - --An improved app discovery view for My Apps is in public preview. The preview shows users more apps in the same space and allows them to scroll between collections. It doesn't currently support drag-and-drop and list view. Users can opt into the preview by selecting Try the preview and opt out by selecting Return to previous view. To learn more about My Apps, see [My Apps portal overview](../manage-apps/myapps-overview.md). --- --- ---### Public Preview - New Azure AD Portal All Devices list --**Type:** Changed feature -**Service category:** Device Registration and Management -**Product capability:** End User Experiences -- --We're enhancing the All Devices list in the Azure AD Portal to make it easier to filter and manage your devices. Improvements include: --All Devices List: --- Infinite scrolling-- More devices properties can be filtered on-- Columns can be reordered via drag and drop-- Select all devices--For more information, see: [Manage devices in Azure AD using the Azure portal](../devices/device-management-azure-portal.md#view-and-filter-your-devices-preview). --- --- ---### Public Preview - ADFS to Azure AD: Persistent NameID for IDP-initiated Apps --**Type:** Changed feature -**Service category:** Enterprise Apps -**Product capability:** SSO - --Previously the only way to have persistent NameID value was to ​configure user attribute with an empty value. Admins can now explicitly configure the NameID value to be persistent ​along with the corresponding format. --For more information, see: [Customize app SAML token claims - Microsoft identity platform | Microsoft Docs](../develop/active-directory-saml-claims-customization.md#attributes). - --- ---### Public Preview - ADFS to Azure Active Directory: Customize attrname-format​ --**Type:** Changed feature -**Service category:** Enterprise Apps -**Product capability:** SSO - --With this new parity update, customers can now integrate non-gallery applications such as Socure DevHub with Azure AD to have SSO via SAML. --For more information, see [Claims mapping policy - Microsoft Entra | Microsoft Docs](../develop/reference-claims-mapping-policy-type.md#claim-schema-entry-elements). - --+ |
active-directory | Lifecycle Workflows Deployment | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/governance/lifecycle-workflows-deployment.md | |
active-directory | Manage Workflow Properties | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/governance/manage-workflow-properties.md | You can update the following basic information without creating a new workflow. - display name - description - whether or not it is enabled.+ - Whether or not workflow schedule is enabled. If you change any other parameters, a new version is required to be created as outlined in the [Managing workflow versions](manage-workflow-tasks.md) article. |
active-directory | Manage Workflow Tasks | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/governance/manage-workflow-tasks.md | |
active-directory | Whats New Docs | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/manage-apps/whats-new-docs.md | Title: "What's new in Azure Active Directory application management" description: "New and updated documentation for the Azure Active Directory application management." Previously updated : 01/05/2023 Last updated : 02/01/2023 +## January 2023 ++### New articles ++- [Configure Datawiza for Azure Active Directory Multi-Factor Authentication and single sign-on to Oracle EBS](datawiza-azure-ad-sso-mfa-oracle-ebs.md) ++### Updated articles ++- [Manage app consent policies](manage-app-consent-policies.md) +- [Assign enterprise application owners](assign-app-owners.md) +- [Configure enterprise application properties](add-application-portal-configure.md) +- [Tutorial: Configure Datawiza to enable Azure Active Directory Multi-Factor Authentication and single sign-on to Oracle JD Edwards](datawiza-azure-ad-sso-oracle-jde.md) +- [Tutorial: Configure Datawiza to enable Azure Active Directory Multi-Factor Authentication and single sign-on to Oracle PeopleSoft](datawiza-azure-ad-sso-oracle-peoplesoft.md) +- [Tutorial: Configure Secure Hybrid Access with Azure Active Directory and Datawiza](datawiza-with-azure-ad.md) +- [Secure hybrid access: Protect legacy apps with Azure Active Directory](secure-hybrid-access.md) +- [Create an enterprise application from a multi-tenant application in Azure Active Directory](create-service-principal-cross-tenant.md) +- [Configure sign-in behavior using Home Realm Discovery](configure-authentication-for-federated-users-portal.md) +- [Secure hybrid access with Azure Active Directory partner integrations](secure-hybrid-access-integrations.md) + ## December 2022 ### Updated articles Welcome to what's new in Azure Active Directory (Azure AD) application managemen - [Tutorial: Configure F5 BIG-IP Access Policy Manager for Kerberos authentication](f5-big-ip-kerberos-advanced.md) - [Tutorial: Configure F5 BIG-IP Easy Button for Kerberos single sign-on](f5-big-ip-kerberos-easy-button.md) - [Tutorial: Configure F5 BIG-IP Easy Button for header-based and LDAP single sign-on](f5-big-ip-ldap-header-easybutton.md)+ ## November 2022 ### Updated articles Welcome to what's new in Azure Active Directory (Azure AD) application managemen - [Tutorial: Configure Secure Hybrid Access with Azure Active Directory and Silverfort](silverfort-azure-ad-integration.md) - [Grant tenant-wide admin consent to an application](grant-admin-consent.md) - [Restore an enterprise application in Azure AD](restore-application.md)--## October 2022 --### Updated articles --- [Configure how users consent to applications](configure-user-consent.md)-- [Tutorial: Configure F5 BIG-IP Access Policy Manager for Kerberos authentication](f5-big-ip-kerberos-advanced.md)-- [Tutorial: Configure F5 BIG-IP Easy Button for Kerberos single sign-on](f5-big-ip-kerberos-easy-button.md)-- [Tutorial: Configure F5 BIG-IP Easy Button for header-based and LDAP single sign-on](f5-big-ip-ldap-header-easybutton.md)-- [Tutorial: Migrate your applications from Okta to Azure Active Directory](migrate-applications-from-okta-to-azure-active-directory.md)-- [Tutorial: Configure Secure Hybrid Access with Azure Active Directory and Silverfort](silverfort-azure-ad-integration.md) |
active-directory | Known Issues | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/managed-identities-azure-resources/known-issues.md | Workaround for managed identities in a subscription that has been moved to anoth For more information, see [Transfer an Azure subscription to a different Azure AD directory](../../role-based-access-control/transfer-subscription.md). +## Error during managed identity assignment operations +In rare cases, you may see error messages indicating errors related to assignment of managed identities with Azure resources. Some of the example error messages are as follows: +- Azure resource ΓÇÿazure-resource-id' does not have access to identity 'managed-identity-id'. +- No managed service identities are associated with resource ΓÇÿazure-resource-id' +- Managed service identities referenced with URL 'https://control-....virtualMachineScaleSets/<vmss_name>/credentials/v2/systemassigned' are not valid. Ensure all assigned identities associated with the resource are valid. ++**Workaround** +In these rare cases the best next steps are ++1. For identities no longer needed to be assigned to the resource, remove them from the resource. +2. For User Assigned Managed Identity, reassign the identity to the Azure resource. +3. For System Assigned Managed Identity, disable the identity and enable it again. ## Next steps |
active-directory | Cross Tenant Synchronization Configure Graph | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/multi-tenant-organizations/cross-tenant-synchronization-configure-graph.md | -This article describes the keys steps to configure cross-tenant synchronization using Microsoft Graph API. When configured, Azure AD automatically provisions and de-provisions B2B users in your target tenant. For detailed steps using the Azure portal, see [Configure cross-tenant synchronization](cross-tenant-synchronization-configure.md). +This article describes the key steps to configure cross-tenant synchronization using Microsoft Graph API. When configured, Azure AD automatically provisions and de-provisions B2B users in your target tenant. For detailed steps using the Azure portal, see [Configure cross-tenant synchronization](cross-tenant-synchronization-configure.md). :::image type="content" source="./media/common/configure-diagram.png" alt-text="Diagram that shows cross-tenant synchronization between source tenant and target tenant." lightbox="./media/common/configure-diagram.png"::: These steps describe how to use Microsoft Graph Explorer (recommended), but you Content-Type: application/json {- "tenantId": "376a1f89-b02f-4a85-8252-2974d1984d14", + "tenantId": "376a1f89-b02f-4a85-8252-2974d1984d14" } ``` |
active-directory | Cross Tenant Synchronization Configure | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/multi-tenant-organizations/cross-tenant-synchronization-configure.md | By the end of this article, you'll be able to: In this step, you automatically redeem invitations so users from the source tenant don't have to accept the consent prompt. This setting must be checked in both the source tenant (outbound) and target tenant (inbound). For more information, see [Automatic redemption setting](cross-tenant-synchronization-overview.md#automatic-redemption-setting). -1. Select the **Trust settings** tab. +1. In the target tenant, on the same **Inbound access settings** page, select the **Trust settings** tab. 1. Check the **Suppress consent prompts for users from the other tenant when they access apps and resources in my tenant** check box. In this step, you automatically redeem invitations so users from the source tena In this step, you automatically redeem invitations in the source tenant. -1. Sign in to the [Azure portal](https://portal.azure.com) as an administrator of the target tenant. +1. Sign in to the [Azure portal](https://portal.azure.com) as an administrator of the source tenant. 1. Select **Azure Active Directory** > **External Identities**. In this step, you automatically redeem invitations in the source tenant. <br/>**Source tenant** -1. Select **Azure Active Directory** > **Cross-tenant synchronization (Preview)**. +1. In the source tenant, select **Azure Active Directory** > **Cross-tenant synchronization (Preview)**. :::image type="content" source="./media/cross-tenant-synchronization-configure/azure-ad-overview.png" alt-text="Screenshot that shows the Azure Active Directory Overview page." lightbox="./media/cross-tenant-synchronization-configure/azure-ad-overview.png"::: In this step, you automatically redeem invitations in the source tenant. <br/>**Source tenant** -1. In the configuration list, select your configuration. +1. In the source tenant, in the configuration list, select your configuration. :::image type="content" source="./media/cross-tenant-synchronization-configure/configuration-select.png" alt-text="Screenshot that shows the Cross-tenant synchronization Configurations page and a new configuration." lightbox="./media/cross-tenant-synchronization-configure/configuration-select.png"::: The Azure AD provisioning service allows you to define who will be provisioned i Start small. Test with a small set of users before rolling out to everyone. When the scope for provisioning is set to assigned users and groups, you can control it by assigning one or two users to the configuration. You can further refine who is in scope for provisioning by creating attribute-based scoping filters, described in the [next step](#step-8-optional-define-who-is-in-scope-for-provisioning-with-scoping-filters). -1. Select **Provisioning** and expand the **Settings** section. +1. In the source tenant, select **Provisioning** and expand the **Settings** section. :::image type="content" source="./media/cross-tenant-synchronization-configure/provisioning-settings-edit.png" alt-text="Screenshot of the Provisioning page that shows the Settings section with the Scope and Provisioning Status options." lightbox="./media/cross-tenant-synchronization-configure/provisioning-settings-edit.png"::: Start small. Test with a small set of users before rolling out to everyone. When Regardless of the value you selected for **Scope** in the previous step, you can further limit which users are synchronized by creating attribute-based scoping filters. -1. Select **Provisioning** and expand the **Mappings** section. +1. In the source tenant, select **Provisioning** and expand the **Mappings** section. 1. Select **Provision Azure Active Directory Users**. Regardless of the value you selected for **Scope** in the previous step, you can Attribute mappings allow you to define how data should flow between the source tenant and target tenant. For information on how to customize the default attribute mappings, see [Tutorial - Customize user provisioning attribute-mappings for SaaS applications in Azure Active Directory](../app-provisioning/customize-application-attributes.md). -1. Select **Provisioning** and expand the **Mappings** section. +1. In the source tenant, select **Provisioning** and expand the **Mappings** section. 1. Select **Provision Azure Active Directory Users**. Attribute mappings allow you to define how data should flow between the source t <br/>**Source tenant** -1. Select **Provisioning** and expand the **Settings** section. +1. In the source tenant, select **Provisioning** and expand the **Settings** section. :::image type="content" source="./media/cross-tenant-synchronization-configure/provisioning-settings-edit.png" alt-text="Screenshot of the Provisioning page that shows the Settings section with the Scope and Provisioning Status options." lightbox="./media/cross-tenant-synchronization-configure/provisioning-settings-edit.png"::: |
active-directory | Pim Email Notifications | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/active-directory/privileged-identity-management/pim-email-notifications.md | Who receives these emails for Azure AD roles depends on your role, the event, an | User | Role activation is pending approval | Role activation request is completed | PIM is enabled | | | | | |-| Privileged Role Administrator</br>(Activated/Eligible) | Yes</br>(only if no explicit approvers are specified) | Yes* | Yes | -| Security Administrator</br>(Activated/Eligible) | No | Yes* | Yes | -| Global Administrator</br>(Activated/Eligible) | No | Yes* | Yes | +| Privileged Role Administrator</br>(Activated) | Yes</br>(only if no explicit approvers are specified) | Yes* | Yes | +| Security Administrator</br>(Activated) | No | Yes* | Yes | +| Global Administrator</br>(Activated) | No | Yes* | Yes | \* If the [**Notifications** setting](pim-how-to-change-default-settings.md) is set to **Enable**. |
aks | Configure Azure Cni Dynamic Ip Allocation | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/aks/configure-azure-cni-dynamic-ip-allocation.md | This article shows you how to use Azure CNI networking for dynamic allocation of * Review the [prerequisites](/configure-azure-cni.md#prerequisites) for configuring basic Azure CNI networking in AKS, as the same prerequisites apply to this article. * Review the [deployment parameters](/configure-azure-cni.md#deployment-parameters) for configuring basic Azure CNI networking in AKS, as the same parameters apply.-* Only linux node clusters and node pools are supported. * AKS Engine and DIY clusters aren't supported. * Azure CLI version `2.37.0` or later. |
aks | Csi Secrets Store Identity Access | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/aks/csi-secrets-store-identity-access.md | Azure AD workload identity (preview) is supported on both Windows and Linux clus EOF ``` -## Use pod-managed identities --Azure Active Directory (Azure AD) pod-managed identities (preview) use AKS primitives to associate managed identities for Azure resources and identities in Azure AD with pods. You can use these identities to grant access to the Azure Key Vault Secrets Provider for Secrets Store CSI driver. --### Prerequisites --- Ensure that the [Azure AD pod identity add-on][aad-pod-identity] has been enabled on your cluster.-- You must be using a Linux-based cluster.--### Use an Azure AD pod-managed identity --1. Follow the instructions in [Use Azure Active Directory pod-managed identities in Azure Kubernetes Service (Preview)][aad-pod-identity-create] to create a cluster identity, assign it permissions, and create a pod identity. Take note of the newly created identity's `clientId` and `name`. --1. Assign permissions to the new identity to enable it to read your key vault and view its contents by running the following commands: -- ```azurecli-interactive - # set policy to access keys in your key vault - az keyvault set-policy -n <keyvault-name> --key-permissions get --spn <pod-identity-client-id> - # set policy to access secrets in your key vault - az keyvault set-policy -n <keyvault-name> --secret-permissions get --spn <pod-identity-client-id> - # set policy to access certs in your key vault - az keyvault set-policy -n <keyvault-name> --certificate-permissions get --spn <pod-identity-client-id> - ``` --1. Create a `SecretProviderClass` by using the following YAML, using your own values for `aadpodidbinding`, `tenantId`, and the objects to retrieve from your key vault: -- ```yml - # This is a SecretProviderClass example using aad-pod-identity to access the key vault - apiVersion: secrets-store.csi.x-k8s.io/v1 - kind: SecretProviderClass - metadata: - name: azure-kvname-podid - spec: - provider: azure - parameters: - usePodIdentity: "true" # Set to true for using aad-pod-identity to access your key vault - keyvaultName: <key-vault-name> # Set to the name of your key vault - cloudName: "" # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud - objects: | - array: - - | - objectName: secret1 - objectType: secret # object types: secret, key, or cert - objectVersion: "" # [OPTIONAL] object versions, default to latest if empty - - | - objectName: key1 - objectType: key - objectVersion: "" - tenantId: <tenant-Id> # The tenant ID of the key vault - ``` --1. Apply the `SecretProviderClass` to your cluster: -- ```bash - kubectl apply -f secretproviderclass.yaml - ``` --1. Create a pod by using the following YAML, using the name of your identity: -- ```yml - # This is a sample pod definition for using SecretProviderClass and aad-pod-identity to access the key vault - kind: Pod - apiVersion: v1 - metadata: - name: busybox-secrets-store-inline-podid - labels: - aadpodidbinding: <name> # Set the label value to the name of your pod identity - spec: - containers: - - name: busybox - image: k8s.gcr.io/e2e-test-images/busybox:1.29-1 - command: - - "/bin/sleep" - - "10000" - volumeMounts: - - name: secrets-store01-inline - mountPath: "/mnt/secrets-store" - readOnly: true - volumes: - - name: secrets-store01-inline - csi: - driver: secrets-store.csi.k8s.io - readOnly: true - volumeAttributes: - secretProviderClass: "azure-kvname-podid" - ``` --1. Apply the pod to your cluster: -- ```bash - kubectl apply -f pod.yaml - ``` --## Use a user-assigned managed identity +## Use the CSI Secret Store addon user-assigned managed identity 1. To access your key vault, you can use the user-assigned managed identity that you created when you [enabled a managed identity on your AKS cluster][use-managed-identity]: Azure Active Directory (Azure AD) pod-managed identities (preview) use AKS primi ```bash kubectl apply -f pod.yaml ```--## Use a system-assigned managed identity --### Prerequisites -->[!IMPORTANT] -> Before you begin this step, [enable system-assigned managed identity][enable-system-assigned-identity] on your AKS cluster's VMs or scale sets. -> --### Usage --1. Verify that your Virtual Machine Scale Set or Availability Set nodes have their own system-assigned identity: -- ```azurecli-interactive - az vmss identity show -g <resource group> -n <vmss scalset name> -o yaml - az vm identity show -g <resource group> -n <vm name> -o yaml - ``` -- >[!NOTE] - > The output should contain `type: SystemAssigned`. Make a note of the `principalId`. - > - > IMDS is looking for a System Assigned Identity on VMSS first, then it will look for a User Assigned Identity and pull that if there is only 1. If there are multiple User Assigned Identities IMDS will throw an error as it does not know which identity to pull. - > --1. To grant your identity permissions that enable it to read your key vault and view its contents, run the following commands: -- ```azurecli-interactive - # set policy to access keys in your key vault - az keyvault set-policy -n <keyvault-name> --key-permissions get --spn <identity-principal-id> - # set policy to access secrets in your key vault - az keyvault set-policy -n <keyvault-name> --secret-permissions get --spn <identity-principal-id> - # set policy to access certs in your key vault - az keyvault set-policy -n <keyvault-name> --certificate-permissions get --spn <identity-principal-id> - ``` --1. Create a `SecretProviderClass` by using the following YAML, using your own values for `keyvaultName`, `tenantId`, and the objects to retrieve from your key vault: -- ```yml - # This is a SecretProviderClass example using system-assigned identity to access your key vault - apiVersion: secrets-store.csi.x-k8s.io/v1 - kind: SecretProviderClass - metadata: - name: azure-kvname-system-msi - spec: - provider: azure - parameters: - usePodIdentity: "false" - useVMManagedIdentity: "true" # Set to true for using managed identity - userAssignedIdentityID: "" # If empty, then defaults to use the system assigned identity on the VM - keyvaultName: <key-vault-name> - cloudName: "" # [OPTIONAL for Azure] if not provided, the Azure environment defaults to AzurePublicCloud - objects: | - array: - - | - objectName: secret1 - objectType: secret # object types: secret, key, or cert - objectVersion: "" # [OPTIONAL] object versions, default to latest if empty - - | - objectName: key1 - objectType: key - objectVersion: "" - tenantId: <tenant-id> # The tenant ID of the key vault - ``` --1. Apply the `SecretProviderClass` to your cluster: -- ```bash - kubectl apply -f secretproviderclass.yaml - ``` --1. Create a pod by using the following YAML: -- ```yml - # This is a sample pod definition for using SecretProviderClass and system-assigned identity to access your key vault - kind: Pod - apiVersion: v1 - metadata: - name: busybox-secrets-store-inline-system-msi - spec: - containers: - - name: busybox - image: k8s.gcr.io/e2e-test-images/busybox:1.29-1 - command: - - "/bin/sleep" - - "10000" - volumeMounts: - - name: secrets-store01-inline - mountPath: "/mnt/secrets-store" - readOnly: true - volumes: - - name: secrets-store01-inline - csi: - driver: secrets-store.csi.k8s.io - readOnly: true - volumeAttributes: - secretProviderClass: "azure-kvname-system-msi" - ``` - ## Next steps To validate that the secrets are mounted at the volume path that's specified in your pod's YAML, see [Use the Azure Key Vault Provider for Secrets Store CSI Driver in an AKS cluster][validate-secrets]. |
aks | Http Proxy | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/aks/http-proxy.md | Some more complex solutions may require creating a chain of trust to establish s The following scenarios are **not** supported: - Different proxy configurations per node pool-- Updating proxy settings post cluster creation+- Updating HTTP/HTTPS proxy settings post cluster creation - User/Password authentication - Custom CAs for API server communication - Windows-based clusters Deploying an AKS cluster with an HTTP proxy configured using an ARM template is In your template, provide values for *httpProxy*, *httpsProxy*, and *noProxy*. If necessary, provide a value for *trustedCa*. Deploy the template, and your cluster should initialize with your HTTP proxy configured on the nodes. -## Handling CA rollover +## Updating Proxy configurations -Values for *httpProxy*, *httpsProxy*, and *noProxy* can't be changed after cluster creation. However, to support rolling CA certs, the value for *trustedCa* can be changed and applied to the cluster with the [az aks update][az-aks-update] command. +Values for *httpProxy*, and *httpsProxy* can't be changed after cluster creation. However, to support rolling CA certs and No Proxy settings, the values for *trustedCa* and *NoProxy* can be changed and applied to the cluster with the [az aks update][az-aks-update] command. -For example, assuming a new file has been created with the base64 encoded string of the new CA cert called *aks-proxy-config-2.json*, the following action updates the cluster: +For example, assuming a new file has been created with the base64 encoded string of the new CA cert called *aks-proxy-config-2.json*, the following action updates the cluster. Or, you need to add new endpoint urls for your applications to No Proxy: ```azurecli az aks update -n $clusterName -g $resourceGroup --http-proxy-config aks-proxy-config-2.json For more information regarding the network requirements of AKS clusters, see [co [az-provider-register]: /cli/azure/provider#az_provider_register [az-extension-add]: /cli/azure/extension#az_extension_add [az-extension-update]: /cli/azure/extension#az-extension-update-[install-azure-cli]: /cli/azure/install-azure-cli +[install-azure-cli]: /cli/azure/install-azure-cli |
aks | Image Cleaner | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/aks/image-cleaner.md | Title: Use ImageCleaner on Azure Kubernetes Service (AKS) -description: Learn how to use ImageCleaner to clean up stale images on Azure Kubernetes Service (AKS) + Title: Use Image Cleaner on Azure Kubernetes Service (AKS) +description: Learn how to use Image Cleaner to clean up stale images on Azure Kubernetes Service (AKS) -# Use ImageCleaner to clean up stale images on your Azure Kubernetes Service cluster (preview) +# Use Image Cleaner to clean up stale images on your Azure Kubernetes Service cluster (preview) -It's common to use pipelines to build and deploy images on Azure Kubernetes Service (AKS) clusters. While great for image creation, this process often doesn't account for the stale images left behind and can lead to image bloat on cluster nodes. These images can present security issues as they may contain vulnerabilities. By cleaning these unreferenced images, you can remove an area of risk in your clusters. When done manually, this process can be time intensive, which ImageCleaner can mitigate via automatic image identification and removal. +It's common to use pipelines to build and deploy images on Azure Kubernetes Service (AKS) clusters. While great for image creation, this process often doesn't account for the stale images left behind and can lead to image bloat on cluster nodes. These images can present security issues as they may contain vulnerabilities. By cleaning these unreferenced images, you can remove an area of risk in your clusters. When done manually, this process can be time intensive, which Image Cleaner can mitigate via automatic image identification and removal. > [!NOTE]-> ImageCleaner is a feature based on [Eraser](https://github.com/Azure/eraser). -> On an AKS cluster, the feature name and property name is `ImageCleaner` while the relevant ImageCleaner pods' names contain `Eraser`. +> Image Cleaner is a feature based on [Eraser](https://github.com/Azure/eraser). +> On an AKS cluster, the feature name and property name is `Image Cleaner` while the relevant Image Cleaner pods' names contain `Eraser`. [!INCLUDE [preview features callout](./includes/preview/preview-callout.md)] Register-AzResourceProvider -ProviderNamespace Microsoft.ContainerService ## Limitations -ImageCleaner does not support the following: +Image Cleaner does not support the following: * ARM64 node pools. For more information, see [Azure Virtual Machines with ARM-based processors][arm-vms]. * Windows node pools. -## How ImageCleaner works +## How Image Cleaner works -When enabled, an `eraser-controller-manager` pod is deployed on each agent node, which will use an `ImageList` CRD to determine unreferenced and vulnerable images. Vulnerability is determined based on a [trivy][trivy] scan, after which images with a `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` classification are flagged. An updated `ImageList` will be automatically generated by ImageCleaner based on a set time interval, and can also be supplied manually. +When enabled, an `eraser-controller-manager` pod is deployed on each agent node, which will use an `ImageList` CRD to determine unreferenced and vulnerable images. Vulnerability is determined based on a [trivy][trivy] scan, after which images with a `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL` classification are flagged. An updated `ImageList` will be automatically generated by Image Cleaner based on a set time interval, and can also be supplied manually. -Once an `ImageList` is generated, ImageCleaner will remove all the images in the list from node VMs. +Once an `ImageList` is generated, Image Cleaner will remove all the images in the list from node VMs. :::image type="content" source="./media/image-cleaner/image-cleaner.jpg" alt-text="A diagram showing ImageCleaner's workflow. The ImageCleaner pods running on the cluster can generate an ImageList, or manual input can be provided."::: ## Configuration options -In addition to choosing between manual and automatic mode, there are several options for ImageCleaner: +In addition to choosing between manual and automatic mode, there are several options for Image Cleaner: |Name|Description|Required| |-|--|--|-|--enable-image-cleaner|Enable the ImageCleaner feature for an AKS cluster|Yes, unless disable is specified| -|--disable-image-cleaner|Disable the ImageCleaner feature for an AKS cluster|Yes, unless enable is specified| -|--image-cleaner-interval-hours|This parameter determines the interval time (in hours) ImageCleaner will use to run. The default value for Azure CLI is one week, the minimum value is 24 hours and the maximum is three months.|Not required for Azure CLI, required for ARM template or other clients| +|--enable-image-cleaner|Enable the Image Cleaner feature for an AKS cluster|Yes, unless disable is specified| +|--disable-image-cleaner|Disable the Image Cleaner feature for an AKS cluster|Yes, unless enable is specified| +|--image-cleaner-interval-hours|This parameter determines the interval time (in hours) Image Cleaner will use to run. The default value for Azure CLI is one week, the minimum value is 24 hours and the maximum is three months.|Not required for Azure CLI, required for ARM template or other clients| > [!NOTE]-> After disabling ImageCleaner, the old configuration still exists. This means that if you enable the feature again without explicitly passing configuration, the existing value will be used rather than the default. +> After disabling Image Cleaner, the old configuration still exists. This means that if you enable the feature again without explicitly passing configuration, the existing value will be used rather than the default. -## Enable ImageCleaner on your AKS cluster +## Enable Image Cleaner on your AKS cluster To create a new AKS cluster using the default interval, use [az aks create][az-aks-create]: az aks update -g MyResourceGroup -n MyManagedCluster \ --enable-image-cleaner ``` -The `--image-cleaner-interval-hours` parameter can be specified at creation time or for an existing cluster. For example, the following command updates the interval for a cluster with ImageCleaner already enabled: +The `--image-cleaner-interval-hours` parameter can be specified at creation time or for an existing cluster. For example, the following command updates the interval for a cluster with Image Cleaner already enabled: ```azurecli-interactive az aks update -g MyResourceGroup -n MyManagedCluster \ az aks update -g MyResourceGroup -n MyManagedCluster \ ``` After the feature is enabled, the `eraser-controller-manager-xxx` pod and `collector-aks-xxx` pod will be deployed.-Based on your configuration, ImageCleaner will generate an `ImageList` containing non-running and vulnerable images at the desired interval. ImageCleaner will automatically remove these images from cluster nodes. +Based on your configuration, Image Cleaner will generate an `ImageList` containing non-running and vulnerable images at the desired interval. Image Cleaner will automatically remove these images from cluster nodes. ## Manually remove images -To manually remove images from your cluster using ImageCleaner, first create an `ImageList`. For example, save the following as `image-list.yml`: +To manually remove images from your cluster using Image Cleaner, first create an `ImageList`. For example, save the following as `image-list.yml`: ```yml apiVersion: eraser.sh/v1alpha1 And apply it to the cluster: kubectl apply -f image-list.yml ``` -A job named `eraser-aks-xxx`will be triggered which causes ImageCleaner to remove the desired images from all nodes. +A job named `eraser-aks-xxx`will be triggered which causes Image Cleaner to remove the desired images from all nodes. -## Disable ImageCleaner +## Disable Image Cleaner -To stop using ImageCleaner, you can disable it via the `--disable-image-cleaner` flag: +To stop using Image Cleaner, you can disable it via the `--disable-image-cleaner` flag: ```azurecli-interactive az aks update -g MyResourceGroup -n MyManagedCluster |
aks | Ingress Tls | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/aks/ingress-tls.md | To use TLS with [Let's Encrypt][lets-encrypt] certificates, you'll deploy [cert- ### [Azure CLI](#tab/azure-cli) -Use `az acr import` to import the following images into your ACR. +* Use `az acr import` to import the following images into your ACR. -```azurecli -REGISTRY_NAME=<REGISTRY_NAME> -CERT_MANAGER_REGISTRY=quay.io -CERT_MANAGER_TAG=v1.8.0 -CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller -CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook -CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector --az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG -az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG -az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG -``` + ```azurecli + REGISTRY_NAME=<REGISTRY_NAME> + CERT_MANAGER_REGISTRY=quay.io + CERT_MANAGER_TAG=v1.8.0 + CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller + CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook + CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector ++ az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG + az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG + az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG + ``` ### [Azure PowerShell](#tab/azure-powershell) -Use `Import-AzContainerRegistryImage` to import the following images into your ACR. +* Use `Import-AzContainerRegistryImage` to import the following images into your ACR. -```azurepowershell -$RegistryName = "<REGISTRY_NAME>" -$ResourceGroup = (Get-AzContainerRegistry | Where-Object {$_.name -eq $RegistryName} ).ResourceGroupName -$CertManagerRegistry = "quay.io" -$CertManagerTag = "v1.8.0" -$CertManagerImageController = "jetstack/cert-manager-controller" -$CertManagerImageWebhook = "jetstack/cert-manager-webhook" -$CertManagerImageCaInjector = "jetstack/cert-manager-cainjector" --Import-AzContainerRegistryImage -ResourceGroupName $ResourceGroup -RegistryName $RegistryName -SourceRegistryUri $CertManagerRegistry -SourceImage "${CertManagerImageController}:${CertManagerTag}" -Import-AzContainerRegistryImage -ResourceGroupName $ResourceGroup -RegistryName $RegistryName -SourceRegistryUri $CertManagerRegistry -SourceImage "${CertManagerImageWebhook}:${CertManagerTag}" -Import-AzContainerRegistryImage -ResourceGroupName $ResourceGroup -RegistryName $RegistryName -SourceRegistryUri $CertManagerRegistry -SourceImage "${CertManagerImageCaInjector}:${CertManagerTag}" -``` + ```azurepowershell + $RegistryName = "<REGISTRY_NAME>" + $ResourceGroup = (Get-AzContainerRegistry | Where-Object {$_.name -eq $RegistryName} ).ResourceGroupName + $CertManagerRegistry = "quay.io" + $CertManagerTag = "v1.8.0" + $CertManagerImageController = "jetstack/cert-manager-controller" + $CertManagerImageWebhook = "jetstack/cert-manager-webhook" + $CertManagerImageCaInjector = "jetstack/cert-manager-cainjector" ++ Import-AzContainerRegistryImage -ResourceGroupName $ResourceGroup -RegistryName $RegistryName -SourceRegistryUri $CertManagerRegistry -SourceImage "${CertManagerImageController}:${CertManagerTag}" + Import-AzContainerRegistryImage -ResourceGroupName $ResourceGroup -RegistryName $RegistryName -SourceRegistryUri $CertManagerRegistry -SourceImage "${CertManagerImageWebhook}:${CertManagerTag}" + Import-AzContainerRegistryImage -ResourceGroupName $ResourceGroup -RegistryName $RegistryName -SourceRegistryUri $CertManagerRegistry -SourceImage "${CertManagerImageCaInjector}:${CertManagerTag}" + ``` When you upgrade your ingress controller, you must pass a parameter to the Helm 1. Get the resource group name of the AKS cluster with the [`az aks show`][az-aks-show] command. -```azurecli-interactive -az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv -``` + ```azurecli-interactive + az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv + ``` 2. Create a public IP address with the *static* allocation method using the [`az network public-ip create`][az-network-public-ip-create] command. The following example creates a public IP address named *myAKSPublicIP* in the AKS cluster resource group obtained in the previous step. -```azurecli-interactive -az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv -``` + ```azurecli-interactive + az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv + ``` > [!NOTE] > Alternatively, you can create an IP address in a different resource group, which you can manage separately from your AKS cluster. If you create an IP address in a different resource group, ensure the following are true: az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eas 4. Add the `--set controller.service.loadBalancerIP="<STATIC_IP>"` parameter. Specify your own public IP address that was created in the previous step. -```azurecli-interactive -DNS_LABEL="<DNS_LABEL>" -NAMESPACE="ingress-basic" -STATIC_IP=<STATIC_IP> + ```azurecli-interactive + DNS_LABEL="<DNS_LABEL>" + NAMESPACE="ingress-basic" + STATIC_IP=<STATIC_IP> -helm upgrade ingress-nginx ingress-nginx/ingress-nginx \ - --namespace $NAMESPACE \ - --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \ - --set controller.service.loadBalancerIP=$STATIC_IP -``` + helm upgrade ingress-nginx ingress-nginx/ingress-nginx \ + --namespace $NAMESPACE \ + --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \ + --set controller.service.loadBalancerIP=$STATIC_IP + ``` ### [Azure PowerShell](#tab/azure-powershell) 1. Get the resource group name of the AKS cluster with the [`Get-AzAksCluster`][get-az-aks-cluster] command. -```azurepowershell-interactive -(Get-AzAksCluster -ResourceGroupName $ResourceGroup -Name myAKSCluster).NodeResourceGroup -``` + ```azurepowershell-interactive + (Get-AzAksCluster -ResourceGroupName $ResourceGroup -Name myAKSCluster).NodeResourceGroup + ``` 2. Create a public IP address with the *static* allocation method using the [`New-AzPublicIpAddress`][new-az-public-ip-address] command. The following example creates a public IP address named *myAKSPublicIP* in the AKS cluster resource group obtained in the previous step. -```azurepowershell-interactive -(New-AzPublicIpAddress -ResourceGroupName MC_myResourceGroup_myAKSCluster_eastus -Name myAKSPublicIP -Sku Standard -AllocationMethod Static -Location eastus).IpAddress -``` + ```azurepowershell-interactive + (New-AzPublicIpAddress -ResourceGroupName MC_myResourceGroup_myAKSCluster_eastus -Name myAKSPublicIP -Sku Standard -AllocationMethod Static -Location eastus).IpAddress + ``` > [!NOTE] > Alternatively, you can create an IP address in a different resource group, which you can manage separately from your AKS cluster. If you create an IP address in a different resource group, ensure the following are true: helm upgrade ingress-nginx ingress-nginx/ingress-nginx \ > * The cluster identity used by the AKS cluster has delegated permissions to the resource group, such as *Network Contributor*. > * Add the `--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>"` parameter. Replace `<RESOURCE_GROUP>` with the name of the resource group where the IP address resides. -3. Add the --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>" parameter. The DNS label can be set either when the ingress controller is first deployed, or it can be configured later. +3. Add the `--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>"` parameter. The DNS label can be set either when the ingress controller is first deployed, or it can be configured later. -4. Add the --set controller.service.loadBalancerIP="<STATIC_IP>" parameter. Specify your own public IP address that was created in the previous step. +4. Add the `--set controller.service.loadBalancerIP="<STATIC_IP>"` parameter. Specify your own public IP address that was created in the previous step. -```azurepowershell-interactive -$DnsLabel = "<DNS_LABEL>" -$Namespace = "ingress-basic" -$StaticIP = "<STATIC_IP>" + ```azurepowershell-interactive + $DnsLabel = "<DNS_LABEL>" + $Namespace = "ingress-basic" + $StaticIP = "<STATIC_IP>" -helm upgrade ingress-nginx ingress-nginx/ingress-nginx ` - --namespace $Namespace ` - --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DnsLabel ` - --set controller.service.loadBalancerIP=$StaticIP -``` + helm upgrade ingress-nginx ingress-nginx/ingress-nginx ` + --namespace $Namespace ` + --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DnsLabel ` + --set controller.service.loadBalancerIP=$StaticIP + ``` For more information, see [Use a static public IP address and DNS label with the #### Use a dynamic public IP address -An Azure public IP address is created for your ingress controller upon creation. The public IP address is static for the lifespan of your ingress controller. The public IP address *doesn't* remain if you delete your ingress controller. If you create a new ingress controller, it will be assigned a new public IP address. +An Azure public IP address is created for your ingress controller upon creation. The public IP address is static for the lifespan of your ingress controller. The public IP address *doesn't* remain if you delete your ingress controller. If you create a new ingress controller, it will be assigned a new public IP address. Your output should look similar to the following sample output. -Use the `kubectl get service` command to get the public IP address for your ingress controller. +* Use the `kubectl get service` command to get the public IP address for your ingress controller. -```console -kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller -``` + ```console + # Get the public IP address for your ingress controller -Your output should look similar to the following example output: + kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller -```console -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR -nginx-ingress-ingress-nginx-controller LoadBalancer 10.0.74.133 EXTERNAL_IP 80:32486/TCP,443:30953/TCP 44s app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx -``` + # Sample output ++ NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR + nginx-ingress-ingress-nginx-controller LoadBalancer 10.0.74.133 EXTERNAL_IP 80:32486/TCP,443:30953/TCP 44s app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx + ``` ### Add an A record to your DNS zone If you're using a custom domain, you need to add an *A* record to your DNS zone. ### [Azure CLI](#tab/azure-cli) -Add an *A* record to your DNS zone with the external IP address of the NGINX service using [`az network dns record-set a add-record`][az-network-dns-record-set-a-add-record]. +* Add an *A* record to your DNS zone with the external IP address of the NGINX service using [`az network dns record-set a add-record`][az-network-dns-record-set-a-add-record]. -```azurecli -az network dns record-set a add-record \ - --resource-group myResourceGroup \ - --zone-name MY_CUSTOM_DOMAIN \ - --record-set-name "*" \ - --ipv4-address MY_EXTERNAL_IP -``` + ```azurecli + az network dns record-set a add-record \ + --resource-group myResourceGroup \ + --zone-name MY_CUSTOM_DOMAIN \ + --record-set-name "*" \ + --ipv4-address MY_EXTERNAL_IP + ``` ### [Azure PowerShell](#tab/azure-powershell) -Add an *A* record to your DNS zone with the external IP address of the NGINX service using [`New-AzDnsRecordSet`][new-az-dns-recordset-create-a-record]. +* Add an *A* record to your DNS zone with the external IP address of the NGINX service using [`New-AzDnsRecordSet`][new-az-dns-recordset-create-a-record]. -```azurepowershell -$Records = @() -$Records += New-AzDnsRecordConfig -IPv4Address <External IP> -New-AzDnsRecordSet -Name "*" ` - -RecordType A ` - -ResourceGroupName <Name of Resource Group for the DNS Zone> ` - -ZoneName <Custom Domain Name> ` - -TTL 3600 ` - -DnsRecords $Records -``` + ```azurepowershell + $Records = @() + $Records += New-AzDnsRecordConfig -IPv4Address <External IP> + New-AzDnsRecordSet -Name "*" ` + -RecordType A ` + -ResourceGroupName <Name of Resource Group for the DNS Zone> ` + -ZoneName <Custom Domain Name> ` + -TTL 3600 ` + -DnsRecords $Records + ``` ### Configure an FQDN for your ingress controller -Optionally, you can configure an FQDN for the ingress controller IP address instead of a custom domain by setting a DNS label. Your FQDN should follow this form: `<CUSTOM LABEL>.<AZURE REGION NAME>.cloudapp.azure.com`. Your DNS label must be unique within its Azure location. +Optionally, you can configure an FQDN for the ingress controller IP address instead of a custom domain by setting a DNS label. Your FQDN should follow this form: `<CUSTOM DNS LABEL>.<AZURE REGION NAME>.cloudapp.azure.com`. ++> [!IMPORTANT] +> Your DNS label must be unique within its Azure location. You can configure your FQDN using one of the following methods: For more information, see [Public IP address DNS name labels](../virtual-network #### Set the DNS label using Azure CLI or Azure PowerShell +Make sure to replace `<DNS_LABEL>` with your unique DNS label. + ### [Azure CLI](#tab/azure-cli) ```azurecli For more information, see [Public IP address DNS name labels](../virtual-network IP="MY_EXTERNAL_IP" # Name to associate with public IP address-DNSNAME="demo-aks-ingress" +DNSLABEL="<DNS_LABEL>" # Get the resource-id of the public IP PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv) # Update public IP address with DNS name-az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME +az network public-ip update --ids $PUBLICIPID --dns-name $DNSLABEL # Display the FQDN az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv $AksIpAddress = "MY_EXTERNAL_IP" $PublicIp = Get-AzPublicIpAddress | Where-Object {$_.IpAddress -eq $AksIpAddress} # Update public IP address with DNS name-$PublicIp.DnsSettings = @{"DomainNameLabel" = "demo-aks-ingress"} +$PublicIp.DnsSettings = @{"DomainNameLabel" = "<DNS_LABEL>"} $UpdatedPublicIp = Set-AzPublicIpAddress -PublicIpAddress $publicIp # Display the FQDN Write-Output $UpdatedPublicIp.DnsSettings.Fqdn You can pass an annotation setting to your Helm chart configuration using the `--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"` parameter. This parameter can be set when the ingress controller is first deployed, or it can be configured later. -The following example shows how to update this setting after the controller has been deployed. +The following example shows how to update this setting after the controller has been deployed. Make sure to replace `<DNS_LABEL>` with your unique DNS label. ### [Azure CLI](#tab/azure-cli) ```bash-DNS_LABEL="<DNS_LABEL>" +DNSLABEL="<DNS_LABEL>" NAMESPACE="ingress-basic" helm upgrade ingress-nginx ingress-nginx/ingress-nginx \ --namespace $NAMESPACE \- --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL + --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNSLABEL ``` ### [Azure PowerShell](#tab/azure-powershell) Before certificates can be issued, cert-manager requires one of the following is For more information, see the [cert-manager issuer][cert-manager-issuer] documentation. -Create a cluster issuer, such as `cluster-issuer.yaml`, using the following example manifest. Replace `MY_EMAIL_ADDRESS` with a valid address from your organization. --```yaml -apiVersion: cert-manager.io/v1 -kind: ClusterIssuer -metadata: - name: letsencrypt -spec: - acme: - server: https://acme-v02.api.letsencrypt.org/directory - email: MY_EMAIL_ADDRESS - privateKeySecretRef: - name: letsencrypt - solvers: - - http01: - ingress: - class: nginx - podTemplate: - spec: - nodeSelector: - "kubernetes.io/os": linux -``` --To create the issuer, use the `kubectl apply` command. +1. Create a cluster issuer, such as `cluster-issuer.yaml`, using the following example manifest. Replace `MY_EMAIL_ADDRESS` with a valid address from your organization. -```console -kubectl apply -f cluster-issuer.yaml --namespace ingress-basic -``` + ```yaml + apiVersion: cert-manager.io/v1 + kind: ClusterIssuer + metadata: + name: letsencrypt + spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: MY_EMAIL_ADDRESS + privateKeySecretRef: + name: letsencrypt + solvers: + - http01: + ingress: + class: nginx + podTemplate: + spec: + nodeSelector: + "kubernetes.io/os": linux + ``` ++2. Apply the issuer using the `kubectl apply` command. ++ ```console + kubectl apply -f cluster-issuer.yaml --namespace ingress-basic + ``` ## Update your ingress routes In the following example, traffic is routed as such: > For example, if your FQDN is *demo-aks-ingress.eastus.cloudapp.azure.com*, replace *hello-world-ingress.MY_CUSTOM_DOMAIN* with *demo-aks-ingress.eastus.cloudapp.azure.com* in `hello-world-ingress.yaml`. > -Create or update the `hello-world-ingress.yaml` file using the following example YAML file. Update the `spec.tls.hosts` and `spec.rules.host` to the DNS name you created in a previous step. --```yaml -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: hello-world-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$2 - nginx.ingress.kubernetes.io/use-regex: "true" - cert-manager.io/cluster-issuer: letsencrypt -spec: - ingressClassName: nginx - tls: - - hosts: - - hello-world-ingress.MY_CUSTOM_DOMAIN - secretName: tls-secret - rules: - - host: hello-world-ingress.MY_CUSTOM_DOMAIN - http: - paths: - - path: /hello-world-one(/|$)(.*) - pathType: Prefix - backend: - service: - name: aks-helloworld-one - port: - number: 80 - - path: /hello-world-two(/|$)(.*) - pathType: Prefix - backend: - service: - name: aks-helloworld-two - port: - number: 80 - - path: /(.*) - pathType: Prefix - backend: - service: - name: aks-helloworld-one - port: - number: 80 --apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: hello-world-ingress-static - annotations: - nginx.ingress.kubernetes.io/ssl-redirect: "false" - nginx.ingress.kubernetes.io/rewrite-target: /static/$2 -spec: - ingressClassName: nginx - tls: - - hosts: - - hello-world-ingress.MY_CUSTOM_DOMAIN - secretName: tls-secret - rules: - - host: hello-world-ingress.MY_CUSTOM_DOMAIN - http: - paths: - - path: /static(/|$)(.*) - pathType: Prefix - backend: - service: - name: aks-helloworld-one - port: - number: 80 -``` --Update the ingress resource using the `kubectl apply` command. --```console -kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic -``` +1. Create or update the `hello-world-ingress.yaml` file using the following example YAML file. Update the `spec.tls.hosts` and `spec.rules.host` to the DNS name you created in a previous step. ++ ```yaml + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: hello-world-ingress + annotations: + nginx.ingress.kubernetes.io/rewrite-target: /$2 + nginx.ingress.kubernetes.io/use-regex: "true" + cert-manager.io/cluster-issuer: letsencrypt + spec: + ingressClassName: nginx + tls: + - hosts: + - hello-world-ingress.MY_CUSTOM_DOMAIN + secretName: tls-secret + rules: + - host: hello-world-ingress.MY_CUSTOM_DOMAIN + http: + paths: + - path: /hello-world-one(/|$)(.*) + pathType: Prefix + backend: + service: + name: aks-helloworld-one + port: + number: 80 + - path: /hello-world-two(/|$)(.*) + pathType: Prefix + backend: + service: + name: aks-helloworld-two + port: + number: 80 + - path: /(.*) + pathType: Prefix + backend: + service: + name: aks-helloworld-one + port: + number: 80 + + apiVersion: networking.k8s.io/v1 + kind: Ingress + metadata: + name: hello-world-ingress-static + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/rewrite-target: /static/$2 + spec: + ingressClassName: nginx + tls: + - hosts: + - hello-world-ingress.MY_CUSTOM_DOMAIN + secretName: tls-secret + rules: + - host: hello-world-ingress.MY_CUSTOM_DOMAIN + http: + paths: + - path: /static(/|$)(.*) + pathType: Prefix + backend: + service: + name: aks-helloworld-one + port: + number: 80 + ``` ++2. Update the ingress resource using the `kubectl apply` command. ++ ```console + kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic + ``` ## Verify a certificate object has been created This article used Helm to install the ingress components, certificates, and samp ### Delete the sample namespace and all resources -To delete the entire sample namespace, use the `kubectl delete` command and specify your namespace name. All the resources in the namespace will be deleted. +Deleting the sample namespace also deletes all the resources in the namespace. -```console -kubectl delete namespace ingress-basic -``` +* Delete the entire sample namespace using the `kubectl delete` command and specifying your namespace name. ++ ```console + kubectl delete namespace ingress-basic + ``` ### Delete resources individually Alternatively, you can delete the resource individually. -First, remove the cluster issuer resources. +1. Remove the cluster issuer resources. -```console -kubectl delete -f cluster-issuer.yaml --namespace ingress-basic -``` + ```console + kubectl delete -f cluster-issuer.yaml --namespace ingress-basic + ``` -List the Helm releases with the `helm list` command. Look for charts named *nginx* and *cert-manager*, as shown in the following example output. +2. List the Helm releases with the `helm list` command. Look for charts named *nginx* and *cert-manager*, as shown in the following example output. -```console -$ helm list --namespace ingress-basic + ```console + $ helm list --namespace ingress-basic -NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION -cert-manager ingress-basic 1 2020-01-15 10:23:36.515514 -0600 CST deployed cert-manager-v0.13.0 v0.13.0 -nginx ingress-basic 1 2020-01-15 10:09:45.982693 -0600 CST deployed nginx-ingress-1.29.1 0.27.0 -``` + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + cert-manager ingress-basic 1 2020-01-15 10:23:36.515514 -0600 CST deployed cert-manager-v0.13.0 v0.13.0 + nginx ingress-basic 1 2020-01-15 10:09:45.982693 -0600 CST deployed nginx-ingress-1.29.1 0.27.0 + ``` -Uninstall the releases with the `helm uninstall` command. The following example uninstalls the NGINX ingress and cert-manager deployments. +3. Uninstall the releases using the `helm uninstall` command. The following example uninstalls the NGINX ingress and cert-manager deployments. -```console -$ helm uninstall cert-manager nginx --namespace ingress-basic + ```console + $ helm uninstall cert-manager nginx --namespace ingress-basic -release "cert-manager" uninstalled -release "nginx" uninstalled -``` + release "cert-manager" uninstalled + release "nginx" uninstalled + ``` -Next, remove the two sample applications. +4. Remove the two sample applications. -```console -kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic -kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic -``` + ```console + kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic + kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic + ``` -Remove the ingress route that directed traffic to the sample apps. +5. Remove the ingress route that directed traffic to the sample apps. -```console -kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic -``` + ```console + kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic + ``` -Finally, you can delete the itself namespace. Use the `kubectl delete` command and specify your namespace name. +6. Delete the itself namespace. Use the `kubectl delete` command and specify your namespace name. -```console -kubectl delete namespace ingress-basic -``` + ```console + kubectl delete namespace ingress-basic + ``` ## Next steps |
api-management | Api Management Policy Expressions | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/api-management/api-management-policy-expressions.md | The `context` variable is implicitly available in every policy [expression](api- |-|-| |`context`|[`Api`](#ref-context-api): [`IApi`](#ref-iapi)<br /><br /> [`Deployment`](#ref-context-deployment)<br /><br /> Elapsed: `TimeSpan` - time interval between the value of `Timestamp` and current time<br /><br /> [`LastError`](#ref-context-lasterror)<br /><br /> [`Operation`](#ref-context-operation)<br /><br /> [`Product`](#ref-context-product)<br /><br /> [`Request`](#ref-context-request)<br /><br /> `RequestId`: `Guid` - unique request identifier<br /><br /> [`Response`](#ref-context-response)<br /><br /> [`Subscription`](#ref-context-subscription)<br /><br /> `Timestamp`: `DateTime` - point in time when request was received<br /><br /> `Tracing`: `bool` - indicates if tracing is on or off <br /><br /> [User](#ref-context-user)<br /><br /> [`Variables`](#ref-context-variables): `IReadOnlyDictionary<string, object>`<br /><br /> `void Trace(message: string)`| |<a id="ref-context-api"></a>`context.Api`|`Id`: `string`<br /><br /> `IsCurrentRevision`: `bool`<br /><br /> `Name`: `string`<br /><br /> `Path`: `string`<br /><br /> `Revision`: `string`<br /><br /> `ServiceUrl`: [`IUrl`](#ref-iurl)<br /><br /> `Version`: `string` |-|<a id="ref-context-deployment"></a>`context.Deployment`|`GatewayId`: `string` (returns 'managed' for managed gateways)<br /><br /> `Region`: `string`<br /><br /> `ServiceId`: `string`<br /><br /> `ServiceName`: `string`<br /><br /> `Certificates`: `IReadOnlyDictionary<string, X509Certificate2>`| +|<a id="ref-context-deployment"></a>`context.Deployment`|[`Gateway`](#ref-context-gateway)<br /><br /> `GatewayId`: `string` (returns 'managed' for managed gateways)<br /><br /> `Region`: `string`<br /><br /> `ServiceId`: `string`<br /><br /> `ServiceName`: `string`<br /><br /> `Certificates`: `IReadOnlyDictionary<string, X509Certificate2>`| +|<a id="ref-context-gateway"></a>`context.Deployment.Gateway`|`Id`: `string` (returns 'managed' for managed gateways)<br /><br /> `InstanceId`: `string` (returns 'managed' for managed gateways)<br /><br /> `IsManaged`: `bool`| |<a id="ref-context-lasterror"></a>`context.LastError`|`Source`: `string`<br /><br /> `Reason`: `string`<br /><br /> `Message`: `string`<br /><br /> `Scope`: `string`<br /><br /> `Section`: `string`<br /><br /> `Path`: `string`<br /><br /> `PolicyId`: `string`<br /><br /> For more information about `context.LastError`, see [Error handling](api-management-error-handling-policies.md).| |<a id="ref-context-operation"></a>`context.Operation`|`Id`: `string`<br /><br /> `Method`: `string`<br /><br /> `Name`: `string`<br /><br /> `UrlTemplate`: `string`| |<a id="ref-context-product"></a>`context.Product`|`Apis`: `IEnumerable<`[`IApi`](#ref-iapi)`>`<br /><br /> `ApprovalRequired`: `bool`<br /><br /> `Groups`: `IEnumerable<`[`IGroup`](#ref-igroup)`>`<br /><br /> `Id`: `string`<br /><br /> `Name`: `string`<br /><br /> `State`: `enum ProductState {NotPublished, Published}`<br /><br /> `SubscriptionLimit`: `int?`<br /><br /> `SubscriptionRequired`: `bool`| |
app-service | App Service Web Tutorial Custom Domain | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/app-service-web-tutorial-custom-domain.md | Title: 'Tutorial: Map existing custom DNS name' + Title: 'Map existing custom DNS name' description: Learn how to add an existing custom DNS domain name (vanity domain) to a web app, mobile app back end, or API app in Azure App Service. keywords: app service, azure app service, domain mapping, domain name, existing domain, hostname, vanity domain ms.assetid: dc446e0e-0958-48ea-8d99-441d2b947a7c- Previously updated : 05/27/2021+ Last updated : 01/31/2023 -# Tutorial: Map an existing custom DNS name to Azure App Service +# Map an existing custom DNS name to Azure App Service -[Azure App Service](overview.md) provides a highly scalable, self-patching web hosting service. This tutorial shows you how to map an existing custom Domain Name System (DNS) name to App Service. To migrate a live site and its DNS domain name to App Service with no downtime, see [Migrate an active DNS name to Azure](manage-custom-dns-migrate-domain.md). +[Azure App Service](overview.md) provides a highly scalable, self-patching web hosting service. This guide shows you how to map an existing custom Domain Name System (DNS) name to App Service. To migrate a live site and its DNS domain name to App Service with no downtime, see [Migrate an active DNS name to Azure](manage-custom-dns-migrate-domain.md). -In this tutorial, you learn how to: +The DNS record type you need to add with your domain provider depends on the domain you want to add to App Service. -> [!div class="checklist"] -> * Map a subdomain by using a [CNAME record](https://en.wikipedia.org/wiki/CNAME_record). -> * Map a root domain by using an [A record](https://en.wikipedia.org/wiki/List_of_DNS_record_types#A). -> * Map a [wildcard domain](https://en.wikipedia.org/wiki/Wildcard_DNS_record) by using a CNAME record. -> * Redirect the default URL to a custom directory. +| Scenario | Example | Recommended DNS record | +| - | - | - | - | +| Root domain | contoso.com | [A record](https://en.wikipedia.org/wiki/List_of_DNS_record_types#A). Don't use the CNAME record for the root record (for information, see [RFC 1912 Section 2.4](https://datatracker.ietf.org/doc/html/rfc1912#section-2.4)). | +| Subdomain | www.contoso.com, my.contoso.com | [CNAME record](https://en.wikipedia.org/wiki/CNAME_record). You can map a subdomain to the app's IP address directly with an A record, but it's possible for [the IP address to change](overview-inbound-outbound-ips.md#when-inbound-ip-changes). The CNAME maps to the app's default hostname instead, which is less susceptible to change. | +| [Wildcard](https://en.wikipedia.org/wiki/Wildcard_DNS_record) | *.contoso.com | [CNAME record](https://en.wikipedia.org/wiki/CNAME_record). | +> [!NOTE] +> For an end-to-end tutorial that shows you how to configure a `www` subdomain and a managed certificate, see [Tutorial: Secure your Azure App Service app with a custom domain and a managed certificate](tutorial-secure-domain-certificate.md). -## 1. Prepare your environment +## Prerequisites * [Create an App Service app](./index.yml), or use an app that you created for another tutorial. The web app's [App Service plan](overview-hosting-plans.md) must be a paid tier and not **Free (F1)**. See [Scale up an app](manage-scale-up.md#scale-up-your-pricing-tier) to update the tier. * Make sure you can edit the DNS records for your custom domain. To edit DNS records, you need access to the DNS registry for your domain provider, such as GoDaddy. For example, to add DNS entries for `contoso.com` and `www.contoso.com`, you must be able to configure the DNS settings for the `contoso.com` root domain. Your custom domains must be in a public DNS zone; private DNS zone is only supported on Internal Load Balancer (ILB) App Service Environment (ASE).-* If you don't have a custom domain yet, you can [purchase an App Service domain](manage-custom-dns-buy-domain.md). +* If you don't have a custom domain yet, you can [purchase an App Service domain](manage-custom-dns-buy-domain.md) instead. -## 2. Get a domain verification ID +## 1. Configure a custom domain -#### Sign in to Azure +1. In the [Azure portal](https://portal.azure.com), navigate to your app's management page. +1. In the left menu for your app, select **Custom domains**. +1. Select **Add custom domain**. -Open the [Azure portal](https://portal.azure.com), and sign in with your Azure account. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-custom-domain.png" alt-text="A screenshot showing how to open the Add custom domain dialog." border="true"::: -#### Select the app in the Azure portal +1. For **Domain provider**, select **All other domain services** to configure a third-party domain. -1. Search for and select **App Services**. + > [!NOTE] + > To configure an App Service domain, see [Buy a custom domain name for Azure App Service](manage-custom-dns-buy-domain.md). -  +1. For **TLS/SSL certificate**, select **App Service Managed Certificate** if your app is in **Basic** tier or higher. If you want to remain in **Shared** tier, or if you want to use your own certificate, select **Add certificate later**. -1. On the **App Services** page, select the name of your Azure app. +1. For **TLS/SSL type**, select the binding type you want. -  + [!INCLUDE [Certificate binding types](../../includes/app-service-ssl-binding-types.md)] - You see the management page of the App Service app. +1. For Domain, specify a fully qualified domain name you want based on the domain you own. The **Hostname record type** box defaults to the recommended DNS record to use, depending on whether the domain is a root domain (like `contoso.com`), a subdomain (like `www.contoso.com`, or a wildcard domain `*.contoso.com`). - To add a custom domain to your app, you need to verify your ownership of the domain by adding a verification ID as a TXT record with your domain provider. +1. Don't select **Validate** yet. -1. In the left pane of your app page, select **Custom domains**. -1. Copy the ID in the **Custom Domain Verification ID** box in the **Custom Domains** page for the next step. +1. For each custom domain in App Service, you need two DNS records with your domain provider. The **Domain validation** section shows you two DNS records that you must add with your domain provider. Select the respective **Copy** button to help you with the next step. -  + The following screenshot shows the default selections for a `www.contoso.com` domain, which shows a CNAME record and a TXT record to add. - > [!WARNING] - > Adding domain verification IDs to your custom domain can prevent dangling DNS entries and help to avoid subdomain takeovers. For custom domains you previously configured without this verification ID, you should protect them from the same risk by adding the verification ID to your DNS record. For more information on this common high-severity threat, see [Subdomain takeover](../security/fundamentals/subdomain-takeover.md). - -<a name="info"></a> + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/configure-custom-domain.png" alt-text="A screenshot showing how to configure a new custom domain, along with a managed certificate." border="true"::: -3. **(A record only)** To map an [A record](https://en.wikipedia.org/wiki/List_of_DNS_record_types#A), you need the app's external IP address. In the **Custom domains** page, copy the value of **IP address**. + > [!WARNING] + > While it's not absolutely required to add the TXT record, it's highly recommended for security. The TXT record is a *domain verification ID* that helps avoid subdomain takeovers from other App Service apps. For custom domains you previously configured without this verification ID, you should protect them from the same risk by adding the verification ID (the TXT record) to your DNS configuration. For more information on this common high-severity threat, see [Subdomain takeover](../security/fundamentals/subdomain-takeover.md). -  +<a name="a" aria-hidden="true"></a> +<a name="enable-a" aria-hidden="true"></a> -## 3. Create the DNS records +<a name="wildcard" aria-hidden="true"></a> -1. Sign in to the website of your domain provider. +<a name="cname" aria-hidden="true"></a> - You can use Azure DNS to manage DNS records for your domain and configure a custom DNS name for Azure App Service. For more information, see [Tutorial: Host your domain in Azure DNS](../dns/dns-delegate-domain-azure-dns.md). +## 2. Create the DNS records -1. Find the page for managing DNS records. - Every domain provider has its own DNS records interface, so consult the provider's documentation. Look for areas of the site labeled **Domain Name**, **DNS**, or **Name Server Management**. - - Often, you can find the DNS records page by viewing your account information and then looking for a link such as **My domains**. Go to that page, and then look for a link that's named something like **Zone file**, **DNS Records**, or **Advanced configuration**. +Select the type of record to create and follow the instructions. You can use either a [CNAME record](https://en.wikipedia.org/wiki/CNAME_record) or an [A record](https://en.wikipedia.org/wiki/List_of_DNS_record_types#A) to map a custom DNS name to App Service. - The following screenshot is an example of a DNS records page: +### [Root domain (e.g. contoso.com)](#tab/root) -  +Create two records according to the following table: -1. Select **Add** or the appropriate widget to create a record. +| Record type | Host | Value | Comments | +| - | - | - | - | +| A | `@` | The app's IP address shown in the **Add custom domain** dialog. | The domain mapping itself (`@` typically represents the root domain). | +| TXT | `asuid` | The domain verification ID shown in the **Add custom domain** dialog. | For root domain, App Service accesses `asuid` TXT record to verify your ownership of the custom domain. | -1. Select the type of record to create and follow the instructions. You can use either a [CNAME record](https://en.wikipedia.org/wiki/CNAME_record) or an [A record](https://en.wikipedia.org/wiki/List_of_DNS_record_types#A) to map a custom DNS name to App Service. + -### DNS record types +### [Subdomain (e.g. www.contoso.com)](#tab/subdomain) -| Scenario | Example | Recommended DNS record | -| - | - | - | - | -| Root domain | contoso.com | [A record](https://en.wikipedia.org/wiki/List_of_DNS_record_types#A). Don't use the CNAME record for the root record (for information, see [RFC 1912 Section 2.4](https://datatracker.ietf.org/doc/html/rfc1912#section-2.4)). | -| Subdomain | www.contoso.com, my.contoso.com | [CNAME record](https://en.wikipedia.org/wiki/CNAME_record). You can map a subdomain to the app's IP address directly with an A record, but it's possible for [the IP address to change](overview-inbound-outbound-ips.md#when-inbound-ip-changes). The CNAME maps to the app's default hostname instead, which is less susceptible to change. | -| [Wildcard](https://en.wikipedia.org/wiki/Wildcard_DNS_record) | *.contoso.com | [CNAME record](https://en.wikipedia.org/wiki/CNAME_record). | -# [A](#tab/a) +#### With an A record -- For a root domain like `contoso.com`, create two records according to the following table:+Create two records according to the following table: - | Record type | Host | Value | Comments | - | - | - | - | - | A | `@` | IP address from [Copy the app's IP address](#2-get-a-domain-verification-id) | The domain mapping itself (`@` typically represents the root domain). | - | TXT | `asuid` | [The verification ID you got earlier](#2-get-a-domain-verification-id) | For root domain, App Service accesses `asuid` TXT record to verify your ownership of the custom domain | - -  - -- To map a subdomain like `www.contoso.com` with an A record instead of a recommended CNAME record, your A record and TXT record should look like the following table instead:+|Record type|Host|Value|Comments| +| | | | | +|A|\<subdomain\> (for example, www)|IP address shown in the **Add custom domain** dialog.| The domain mapping itself. | +|TXT|asuid.\<subdomain\> (for example, asuid.www)|The domain verification ID shown in the **Add custom domain** dialog.| App Service accesses the `asuid.<subdomain>` TXT record to verify your ownership of the custom domain. | - |Record type|Host|Value| Comments | - | | | | | - |A|\<subdomain\> (for example, www)|IP address from [Copy the app's IP address](#2-get-a-domain-verification-id)|| - |TXT|asuid.\<subdomain\> (for example, asuid.www)|[The verification ID you got earlier](#2-get-a-domain-verification-id)|| + -  - -# [CNAME](#tab/cname) +#### With a CNAME record -For a subdomain like `www` in `www.contoso.com`, create two records according to the following table: +Create two records according to the following table: | Record type | Host | Value | Comments | | - | - | - | | CNAME | `<subdomain>` (for example, `www`) | `<app-name>.azurewebsites.net` | The domain mapping itself. |-| TXT | `asuid.<subdomain>` (for example, `asuid.www`) | [The verification ID you got earlier](#2-get-a-domain-verification-id) | App Service accesses the `asuid.<subdomain>` TXT record to verify your ownership of the custom domain. | +| TXT | `asuid.<subdomain>` (for example, `asuid.www`) | The domain verification ID shown in the **Add custom domain** dialog. | App Service accesses the `asuid.<subdomain>` TXT record to verify your ownership of the custom domain. | - -# [Wildcard (CNAME)](#tab/wildcard) ++### [Wildcard (CNAME)](#tab/wildcard) For a wildcard name like `*` in `*.contoso.com`, create two records according to the following table: | Record type | Host | Value | Comments |-| - | - | - | +| - | - | - | - | | CNAME | `*` | `<app-name>.azurewebsites.net` | The domain mapping itself. |-| TXT | `asuid` | [The verification ID you got earlier](#2-get-a-domain-verification-id) | App Service accesses the `asuid` TXT record to verify your ownership of the custom domain. | +| TXT | `asuid` | The domain verification ID shown in the **Add custom domain** dialog. | App Service accesses the `asuid` TXT record to verify your ownership of the custom domain. | - --> [!NOTE] -> For certain providers, such as GoDaddy, changes to DNS records don't become effective until you select a separate **Save Changes** link. --<a name="a" aria-hidden="true"></a> --<a name="enable-a" aria-hidden="true"></a> --<a name="wildcard" aria-hidden="true"></a> --<a name="cname" aria-hidden="true"></a> --## 4. Enable the mapping in your app -After you [create DNS records](#3-create-the-dns-records), you enable the mapping in your app. -# [A](#tab/a) --1. In the left pane of the app page in the Azure portal, select **Custom domains**. --  --1. Select **Add custom domain**. --  --1. Type the fully qualified domain name that you configured the A record for, such as `contoso.com`. +-- -1. Select **Validate**. The **Add custom domain** page is shown. +## 3. Validate and complete -1. Make sure that **Hostname record type** is set to **A record (example.com)**. Select **Add custom domain**. +1. Back in the **Add custom domain** dialog in the Azure portal, select **Validate**. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/configure-custom-domain-validate.png" alt-text="A screenshot showing how to validate your DNS record settings in the Add a custom domain dialog." border="true"::: - It might take some time for the new custom domain to be reflected in the app's **Custom Domains** page. Refresh the browser to update the data. +1. If the **Domain validation** section shows green check marks next for both domain records, then you've configured them correctly. Select **Add**. If you see any errors or warnings, fix it in the DNS record settings on your domain provider's website. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/configure-custom-domain-add.png" alt-text="A screenshot showing the Add button activated after validation." border="true"::: > [!NOTE]- > A warning label for your custom domain means that it's not yet bound to a TLS/SSL certificate. Any HTTPS request from a browser to your custom domain will receive an error or warning, depending on the browser. To add a TLS binding, see [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md). - - If you missed a step or made a typo somewhere earlier, a verification error appears at the bottom of the page. - -  + > If you configured the TXT record but not the A or CNAME record, App Service treats it as a [domain migration](manage-custom-dns-migrate-domain.md) scenario and allows the validation to succeed, but you won't see green check marks next to the records. -# [CNAME](#tab/cname) +1. You should see the custom domain added to the list. You may also see a red X with **No binding**. -1. In the left pane of the app page in the Azure portal, select **Custom domains**. + If you selected **App Service Managed Certificate** earlier, wait a few minutes for App Service to create the managed certificate for your custom domain. When the process is complete, the red X becomes a green check mark with **Secured**. If you selected **Add certificate later**, this red X will remain until you [add a private certificate for the domain](configure-ssl-certificate.md) and [configure the binding](configure-ssl-bindings.md). -  --1. Select **Add custom domain**. --  --1. Type the fully qualified domain name that you added a CNAME record for, such as `www.contoso.com`. --1. Select **Validate**. The **Add custom domain** page appears. --1. Make sure that **Hostname record type** is set to **CNAME (www\.example.com or any subdomain)**. Select **Add custom domain**. --  -- It might take some time for the new custom domain to be reflected in the app's **Custom Domains** page. Refresh the browser to update the data. --  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-custom-domain-complete.png" alt-text="A screenshot showing the custom domains page with the new secured custom domain." border="true"::: > [!NOTE]- > A warning label for your custom domain means that it's not yet bound to a TLS/SSL certificate. Any HTTPS request from a browser to your custom domain will receive an error or warning, depending on the browser. To add a TLS binding, see [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md). -- If you missed a step or made a typo somewhere earlier, a verification error appears at the bottom of the page. --  -+ > Unless you configure a certificate binding for your custom domain, Any HTTPS request from a browser to the domain will receive an error or warning, depending on the browser. -# [Wildcard (CNAME)](#tab/wildcard) --1. In the left pane of the app page in the Azure portal, select **Custom domains**. --  --1. Select **Add custom domain**. --  --1. Type a fully qualified domain name that matches the wildcard domain. For example, for the example `*.contoso.com`, you can use `sub1.contoso.com`, `sub2.contoso.com`, `*.contoso.com`, or any other string that matches the wildcard pattern. Then, select **Validate**. -- The **Add custom domain** button is activated. --1. Make sure that **Hostname record type** is set to **CNAME record (www\.example.com or any subdomain)**. Select **Add custom domain**. --  -- It might take some time for the new custom domain to be reflected in the app's **Custom Domains** page. Refresh the browser to update the data. -- > [!NOTE] - > A warning label for your custom domain means that it's not yet bound to a TLS/SSL certificate. Any HTTPS request from a browser to your custom domain will receive an error or warning, depending on the browser. To add a TLS binding, see [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md). ----## 5. Test in a browser +## 4. Test in a browser Browse to the DNS names that you configured earlier. Browse to the DNS names that you configured earlier. <a name="resolve-404-not-found" aria-hidden="true"></a> -If you receive an HTTP 404 (Not Found) error when you browse to the URL of your custom domain, the two most common causes are: +If you receive an HTTP 404 (Not Found) error when you browse to the URL of your custom domain, the two most-likely causes are: ++- The browser client has cached the old IP address of your domain. Clear the cache, and test DNS resolution again. On a Windows machine, you clear the cache with `ipconfig /flushdns`. +- You configured an IP-based certificate binding, and the app's IP address has changed because of it. [Remap the A record](configure-ssl-bindings.md#remap-records-for-ip-ssl) in your DNS entries to the new IP address. -* The custom domain configured is missing an A record or a CNAME record. You may have deleted the DNS record after you've enabled the mapping in your app. Check if the DNS records are properly configured using an <a href="https://www.nslookup.io/">online DNS lookup</a> tool. -* The browser client has cached the old IP address of your domain. Clear the cache, and test DNS resolution again. On a Windows machine, you clear the cache with `ipconfig /flushdns`. +If you receive a `Page not secure` warning or error, it's because your domain doesn't have a certificate binding yet. [Add a private certificate for the domain](configure-ssl-certificate.md) and [configure the binding](configure-ssl-bindings.md). ## (Optional) Automate with scripts If you receive an HTTP 404 (Not Found) error when you browse to the URL of your ## Next steps +> [!div class="nextstepaction"] +> [Purchase an App Service domain](manage-custom-dns-buy-domain.md). + > [!div class="nextstepaction"] > [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md)+ |
app-service | Configure Domain Traffic Manager | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/configure-domain-traffic-manager.md | Once you have finished adding or modifying DNS records at your domain provider, Since Traffic Manager only supports custom domain mapping with CNAME records, and because DNS standards don't support CNAME records for mapping root domains (for example, **contoso.com**), Traffic Manager doesn't support mapping to root domains. To work around this issue, use a URL redirect from at the app level. In ASP.NET Core, for example, you can use [URL Rewriting](/aspnet/core/fundamentals/url-rewriting). Then, use Traffic Manager to load balance the subdomain (**www.contoso.com**). Another approach is you can [create an alias record for your domain name apex to reference an Azure Traffic Manager profile](../dns/tutorial-alias-tm.md). An example is contoso.com. Instead of using a redirecting service, you can configure Azure DNS to reference a Traffic Manager profile directly from your zone. -For high availability scenarios, you can implement a load-balancing DNS setup without Traffic Manager by creating multiple *A records* that point from the root domain to each app copy's IP address. Then, [map the same root domain to all the app copies](app-service-web-tutorial-custom-domain.md#3-create-the-dns-records). Since the same domain name cannot be mapped to two different apps in the same region, this setup only works when your app copies are in different regions. +For high availability scenarios, you can implement a load-balancing DNS setup without Traffic Manager by creating multiple *A records* that point from the root domain to each app copy's IP address. Then, [map the same root domain to all the app copies](app-service-web-tutorial-custom-domain.md#2-create-the-dns-records). Since the same domain name cannot be mapped to two different apps in the same region, this setup only works when your app copies are in different regions. ## Enable custom domain After the records for your domain name have propagated, use the browser to verify that your custom domain name resolves to your App Service app. |
app-service | Configure Ssl Bindings | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/configure-ssl-bindings.md | Title: Secure a custom DNS with a TLS/SSL binding description: Secure HTTPS access to your custom domain by creating a TLS/SSL binding with a certificate. Improve your website's security by enforcing HTTPS or TLS 1.2. tags: buy-ssl-certificates -+ Last updated 04/27/2022 Securing a [custom domain](app-service-web-tutorial-custom-domain.md) with a cer - [Add a private certificate to App Service](configure-ssl-certificate.md) that satisfies all the [private certificate requirements](configure-ssl-certificate.md#private-certificate-requirements). - Create a TLS binding to the corresponding custom domain. This second step is covered by this article. -In this tutorial, you learn how to: --> [!div class="checklist"] -> * Upgrade your app's pricing tier -> * Secure a custom domain with a certificate -> * Enforce HTTPS -> * Enforce TLS 1.1/1.2 -> * Automate TLS management with scripts - ## Prerequisites To follow this how-to guide: To follow this how-to guide: - [Add a private certificate to your app](configure-ssl-certificate.md) > [!NOTE]-> The easiest way to add a private certificate is to [create a free App Service managed certificate](configure-ssl-certificate.md#create-a-free-managed-certificate). +> The easiest way to add a private certificate is to [create a free App Service managed certificate with your custom domain](tutorial-secure-domain-certificate.md). + [!INCLUDE [Prepare your web app](../../includes/app-service-ssl-prepare-app.md)] If your app has no certificate for the selected custom domain, then you have two Use the following table to help you configure the TLS binding in the **TLS/SSL Binding** dialog, then click **Add Binding**. -| Setting | Description | -|-|-| -| Custom domain | The domain name to add the TLS/SSL binding for. | -| Private Certificate Thumbprint | The certificate to bind. | -| TLS/SSL Type | <ul><li>**[SNI SSL](https://en.wikipedia.org/wiki/Server_Name_Indication)** - Multiple SNI SSL bindings may be added. This option allows multiple TLS/SSL certificates to secure multiple domains on the same IP address. Most modern browsers (including Internet Explorer, Chrome, Firefox, and Opera) support SNI (for more information, see [Server Name Indication](https://wikipedia.org/wiki/Server_Name_Indication)).</li><li>**IP SSL** - Only one IP SSL binding may be added. This option allows only one TLS/SSL certificate to secure a dedicated public IP address. After you configure the binding, follow the steps in [Remap records for IP SSL](#remap-records-for-ip-ssl).<br/>IP SSL is supported only in **Standard** tier or above. </li></ul> | Once the operation is complete, the custom domain's TLS/SSL state is changed to **Secure**. There are two changes you need to make, potentially: - By default, your app uses a shared public IP address. When you bind a certificate with IP SSL, App Service creates a new, dedicated IP address for your app. If you mapped an A record to your app, update your domain registry with this new, dedicated IP address. - Your app's **Custom domain** page is updated with the new, dedicated IP address. [Copy this IP address](app-service-web-tutorial-custom-domain.md#info), then [remap the A record](app-service-web-tutorial-custom-domain.md#3-create-the-dns-records) to this new IP address. + Your app's **Custom domain** page is updated with the new, dedicated IP address. Copy this IP address, then [remap the A record](app-service-web-tutorial-custom-domain.md#2-create-the-dns-records) to this new IP address. -- If you have an SNI SSL binding to `<app-name>.azurewebsites.net`, [remap any CNAME mapping](app-service-web-tutorial-custom-domain.md#3-create-the-dns-records) to point to `sni.<app-name>.azurewebsites.net` instead (add the `sni` prefix).+- If you have an SNI SSL binding to `<app-name>.azurewebsites.net`, [remap any CNAME mapping](app-service-web-tutorial-custom-domain.md#2-create-the-dns-records) to point to `sni.<app-name>.azurewebsites.net` instead (add the `sni` prefix). ## Test HTTPS |
app-service | Configure Ssl Certificate | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/configure-ssl-certificate.md | -# Secure connections by adding and managing TLS/SSL certificates in Azure App Service +# Add and manage TLS/SSL certificates in Azure App Service You can add digital security certificates to [use in your application code](configure-ssl-certificate-in-code.md) or to [secure custom DNS names](configure-ssl-bindings.md) in [Azure App Service](overview.md), which provides a highly scalable, self-patching web hosting service. Currently called Transport Layer Security (TLS) certificates, also previously known as Secure Socket Layer (SSL) certificates, these private or public certificates help you secure internet connections by encrypting data sent between your browser, websites that you visit, and the website server. |
app-service | Integrate With Application Gateway | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/environment/integrate-with-application-gateway.md | To integrate your application gateway with your ILB App Service environment, you ### ILB App Service environment -For details on how to create an ILB App Service environment, see [Create an ASE in the Azure portal][creation] and [Create an ASE with ARM][createfromtemplate]. +For details on how to create an ILB App Service environment, see [Create an ASE in the Azure portal][creation] and [Create an ASE with ARM template][createfromtemplate]. * After ILB ASE is created, the default domain is `<YourAseName>.appserviceenvironment.net`. You need to create an App Service plan and an app in your ILB ASE. When creating ### A public DNS name to the application gateway To connect to the application gateway from internet, you need a routable domain name. In this case, I used a routable domain name `asabuludemo.com` and planning to connect to an App Service with this domain name `app.asabuludemo.com`. The IP addresses mapped to this app domain name need to set to the public IP after the application gateway created.-With a public domain mapped to the application gateway, you don't need to configure a custom domain in App Service. You can buy a custom domain name with [App Service Domains](../manage-custom-dns-buy-domain.md#buy-an-app-service-domain). +With a public domain mapped to the application gateway, you don't need to configure a custom domain in App Service. You can buy a custom domain name with [App Service Domains](../manage-custom-dns-buy-domain.md#buy-and-map-an-app-service-domain). ### A valid public certificate In the Azure portal, select **New** > **Network** > **Application Gateway** to c 4. Configuration setting - In **Configuration** setting, you need to add a routing rule by clicking **Add a routing rule** icon. + In **Configuration** setting, you need to add a routing rule by selecting **Add a routing rule** icon. :::image type="content" source="./media/integrate-with-application-gateway/configuration.png" alt-text="Screenshot of adding a routing rule in configuration setting."::: In the Azure portal, select **New** > **Network** > **Application Gateway** to c | Host type | Multiple/Wildcard | Set to multiple or wildcard website name if listener type is set to multi-sites. | | Host name | For example: `app.asabuludemo.com` | Set to a routable domain name for App Service | - :::image type="content" source="./media/integrate-with-application-gateway/https-routing-rule.png" alt-text="H T T P S listener of the application gateway Routing Rule."::: + :::image type="content" source="./media/integrate-with-application-gateway/https-routing-rule.png" alt-text="HTTPS listener of the application gateway Routing Rule."::: - * You have to configure a **Backend Pool** and **HTTP setting** in **Backend targets**. The Backend pool was configured in previously steps. Click **Add new** link to add an HTTP setting. + * You have to configure a **Backend Pool** and **HTTP setting** in **Backend targets**. The Backend pool was configured in previously steps. Select **Add new** link to add an HTTP setting. :::image type="content" source="./media/integrate-with-application-gateway/add-new-http-setting.png" alt-text="Screenshot of adding new link to add an H T T P setting."::: In the Azure portal, select **New** > **Network** > **Application Gateway** to c ## Configure an application gateway integration with ILB ASE -To access ILB ASE from the application gateway, you need to check if a virtual network link to private DNS zone. If there is no virtual network linked to your application gateway's VNet, add a virtual network link with following steps. +To access ILB ASE from the application gateway, you need to check if a virtual network link to private DNS zone. If there's no virtual network linked to your application gateway's VNet, add a virtual network link with following steps. ### Configure virtual network links with a private DNS zone |
app-service | Manage Backup | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/manage-backup.md | In [Azure App Service](overview.md), you can easily restore app backups. You can Backup and restore are supported in **Basic**, **Standard**, **Premium**, and **Isolated** tiers. For **Basic** tier, only the production slot can be backed up and restored. For more information about scaling your App Service plan to use a higher tier, see [Scale up an app in Azure](manage-scale-up.md). > [!NOTE]-> Support in App Service environments (ASE) V2 and V3 is in preview. For App Service environments: +> For App Service environments: > > - Automatic backups can be restored to a target app within the ASE itself, not in another ASE. > - Custom backups can be restored to a target app in another ASE, such as from a V2 ASE to a V3 ASE. Backup and restore are supported in **Basic**, **Standard**, **Premium**, and ** There are two types of backups in App Service. Automatic backups made for your app regularly as long as it's in a supported pricing tier. Custom backups require initial configuration, and can be made on-demand or on a schedule. The following table shows the differences between the two types. -||Automatic backups | Custom backups | +|Feature|Automatic backups | Custom backups | |-|-|-| | Pricing tiers | **Basic**, **Standard**, **Premium**. | **Basic**, **Standard**, **Premium**, **Isolated**. | | Configuration required | No. | Yes. | Each backup is a complete offline copy of your app, not an incremental update. #### Does Azure Functions support automatic backups? -Automatic backups are available in preview for Azure Functions in [dedicated (App Service)](../azure-functions/dedicated-plan.md) **Basic** or **Standard** or **Premium** tiers. Function apps in the [**Consumption**](../azure-functions/consumption-plan.md) or [**Elastic Premium**](../azure-functions/functions-premium-plan.md) pricing tiers aren't supported for automatic backups. +Automatic backups are available for Azure Functions in [dedicated (App Service)](../azure-functions/dedicated-plan.md) **Basic** or **Standard** or **Premium** tiers. Function apps in the [**Consumption**](../azure-functions/consumption-plan.md) or [**Elastic Premium**](../azure-functions/functions-premium-plan.md) pricing tiers aren't supported for automatic backups. #### What's included in an automatic backup? |
app-service | Manage Custom Dns Buy Domain | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/manage-custom-dns-buy-domain.md | Title: Buy a custom domain name + Title: Buy a custom domain description: Learn how to buy an App Service domain and use it as a custom domain for your app Azure App Service. ms.assetid: 70fb0e6e-8727-4cca-ba82-98a4d21586ff Previously updated : 11/30/2020 Last updated : 01/31/2023 -# Buy a custom domain name for Azure App Service +# By an App Service domain and configure an app with it -App Service domains are custom domains that are managed directly in Azure. They make it easy to manage custom domains for [Azure App Service](overview.md). This tutorial shows you how to buy an App Service domain and assign DNS names to Azure App Service. --For Azure VM or Azure Storage, see [Assign App Service domain to Azure VM or Azure Storage](https://azure.github.io/AppService/2017/07/31/Assign-App-Service-domain-to-Azure-VM-or-Azure-Storage). For Cloud Services, see -[Configuring a custom domain name for an Azure cloud service](../cloud-services/cloud-services-custom-domain-name-portal.md). +App Service domains are custom domains that are managed directly in Azure. They make it easy to manage custom domains for [Azure App Service](overview.md). This article shows you how to buy an App Service domain and configure an App Service app with it. ## Prerequisites -To complete this tutorial: - * [Create an App Service app](./index.yml), or use an app that you created for another tutorial. The app should be in an Azure Public region. At this time, Azure National Clouds are not supported.-* [Remove the spending limit on your subscription](../cost-management-billing/manage/spending-limit.md#remove). You cannot buy App Service domains with free subscription credits. +* To use an App Service domain, the app's [App Service plan](overview-hosting-plans.md) must be a paid tier and not **Free (F1)**. See [Scale up an app](manage-scale-up.md#scale-up-your-pricing-tier) to update the tier. +* [Remove the spending limit on your subscription](../cost-management-billing/manage/spending-limit.md#remove). -## Buy an App Service domain +## Buy and map an App Service domain For pricing information on App Service domains, visit the [App Service Pricing page](https://azure.microsoft.com/pricing/details/app-service/windows/) and scroll down to App Service Domain. -1. Open the [Azure portal](https://portal.azure.com) and sign in with your Azure account. --1. In the search bar, search for and select **App Service Domains**. --  --1. In the **App Service Domains** view, click **Add**. +1. In the [Azure portal](https://portal.azure.com), navigate to your app's management page. +1. In the left menu for your app, select **Custom domains**. +1. Select **Buy App Service domain**. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-app-service-domain.png" alt-text="A screenshot showing how to open the App Service domain wizard." border="true"::: -1. Select **Click to try the newer version of the App Service Domains create experience**. --  --### Basics tab + > [!NOTE] + > You can also create an App Service domain independently from an app by going to the App Service Domains view and select **Add**, or navigating to [the create page directly](https://portal.azure.com/#create/Microsoft.Domain). But since it's independent from your app, you won't be able to assign hostnames like `www` to your app as if you launch it from your app's **Custom domains** page. -1. In the **Basics** tab, configure the settings using the following table: +1. In the **Basics** tab, configure the settings using the following table: | Setting | Description | | -- | -- | | **Subscription** | The subscription to use to buy the domain. | | **Resource Group** | The resource group to put the domain in. For example, the resource group your app is in. |- | **Domain** | Type the domain you want. For example, **contoso.com**. If the domain you want is not available, you can select from a list of suggestions of available domains, or try a different domain. | + | **Domain** | Type the domain you want. For example, **contoso.com**. If the domain you want isn't available, you can select from a list of suggestions of available domains, or try a different domain. | > [!NOTE] > The following [top-level domains](https://wikipedia.org/wiki/Top-level_domain) are supported by App Service domains: _com_, _net_, _co.uk_, _org_, _nl_, _in_, _biz_, _org.uk_, and _co.in_. > > -2. When finished, click **Next: Contact information**. +1. Select **Next: Contact information** and supply your information as required by [ICANN](https://go.microsoft.com/fwlink/?linkid=2116641) for the domain registration. -### Contact information tab + It's important that you fill out all required fields with as much accuracy as possible. Incorrect data for contact information can result in failure to buy the domain. -1. Supply your information as required by [ICANN](https://go.microsoft.com/fwlink/?linkid=2116641) for the domain registration. +1. Select **Next: Hostname assignment** and verify the default hostnames to map to your app: - It is important that you fill out all required fields with as much accuracy as possible. Incorrect data for contact information can result in failure to buy the domain. --1. When finished, click **Next: Advanced**. + | Hostname | Description | + | -- | -- | + | **root(@)** | The root or apex subdomain. If you buy the `contoso.com` domain, then it's the root domain. Select **No** if you don't want to map it to your app. | + | **'www' subdomain** | If you buy the `contoso.com` domain, the `www` subdomain would be `www.contoso.com`. Select **No** if you don't want to map it to your app. | -### Advanced tab + > [!NOTE] + > If you didn't launch the App Service domain wizard from an app's **Custom domains** page, you won't see this tab. You can still add them later by following the steps at [Map a hostname manually](#map-a-hostname-manually). -1. In the **Advanced** tab, configure the optional settings: +1. Select **Next: Advanced** and configure the optional settings: | Setting | Description | | -- | -- |- | **Auto renewal** | Enabled by default. Your App Service domain is registered to you at one-year increments. Auto renewal makes sure that your domain registration doesn't expire and that you retain ownership of the domain. Your Azure subscription is automatically charged the yearly domain registration fee at the time of renewal. To opt out, select **Disable**. If auto-renewal is disabled, you can [renew it manually](#renew-the-domain). | + | **Auto renewal** | Your App Service domain is registered to you at one-year increments. Enable auto renewal so that your domain registration doesn't expire and that you retain ownership of the domain. Your Azure subscription is automatically charged the yearly domain registration fee at the time of renewal. If you leave it disabled, you must [renew it manually](#renew-the-domain). | | **Privacy protection** | Enabled by default. Privacy protection hides your domain registration contact information from the WHOIS database. Privacy protection is already included in the yearly domain registration fee. To opt out, select **Disable**. | -2. When finished, click **Next: Tags**. +1. Select **Next: Tags** and set the tags you want for your App Service domain. Tagging isn't required for using App Service domains, but is a [feature in Azure that helps you manage your resources](../azure-resource-manager/management/tag-resources.md). -### Finish --1. In the **Tags** tab, set the tags you want for your App Service domain. Tagging is not required for using App Service domains, but is a [feature in Azure that helps you manage your resources](../azure-resource-manager/management/tag-resources.md). --1. Click **Next: Review + create**. --1. In the **Review + create** tab, review your domain order. When finished, click **Create**. +1. Select **Next: Review + create** and review your domain order. When finished, select **Create**. > [!NOTE] > App Service Domains use GoDaddy for domain registration and Azure DNS to host the domains. In addition to the yearly domain registration fee, usage charges for Azure DNS apply. For information, see [Azure DNS Pricing](https://azure.microsoft.com/pricing/details/dns/). > > -1. When the domain registration is complete, you see a **Go to resource** button. Select it to see it's management page. +1. When the domain registration is complete, you see a **Go to resource** button. Select it to see its management page. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/deployment-complete.png" alt-text="A screenshot showing App Service domain creation completed." border="true"::: You're now ready to assign an App Service app to this custom domain. > [!NOTE]-> Depending on the subscription type, a sufficient payment history may be required prior to creating an App Service Domain. -> -> If you have made payments and are still running into this error, you can contact support and provide proof of payments. --## Prepare the app --To map a custom DNS name to a web app, the web app's [App Service plan](https://azure.microsoft.com/pricing/details/app-service/) must be a paid tier (Shared, Basic, Standard, Premium, or Consumption for Azure Functions). In this step, you make sure that the App Service app is in the supported pricing tier. ---### Navigate to the app in the Azure portal --1. From the top search bar, search for and select **App Services**. --  --1. Select the name of the app. --  -- You see the management page of the App Service app. +> Depending on the subscription type, a sufficient payment history may be required prior to creating an App Service domain. -### Check the pricing tier +## Map a hostname manually -1. In the left navigation of the app page, scroll to the **Settings** section and select **Scale up (App Service plan)**. +If launched from an app's **Custom domains** page, the App Service domain wizard already lets you map the root domain (like `contoso.com`) and the `www` subdomain (like `www.contoso.com`) to your app. You can map any other subdomain to your app, like `shoppingcart` (as in `shoppingcart.contoso.com`). -  --1. The app's current tier is highlighted by a blue border. Check to make sure that the app is not in the **F1** tier. Custom DNS is not supported in the **F1** tier. -- :::image type="content" source="./media/app-service-web-tutorial-custom-domain/check-pricing-tier.png" alt-text="Screenshot of the left navigation menu of the app page with Scale up (App Service plan) selected."::: --1. If the App Service plan is not in the **F1** tier, close the **Scale up** page and skip to [Buy the domain](#buy-an-app-service-domain). --### Scale up the App Service plan --1. Select any of the non-free tiers (**D1**, **B1**, **B2**, **B3**, or any tier in the **Production** category). For additional options, click **See additional options**. --1. Click **Apply**. -- :::image type="content" source="./media/app-service-web-tutorial-custom-domain/choose-pricing-tier.png" alt-text="Screenshot of the custom domain pricing tiers in the Production category with the Production tab, B1 plan, and the Apply button highlighted."::: -- When you see the following notification, the scale operation is complete. --  +1. In the [Azure portal](https://portal.azure.com), navigate to your app's management page. +1. In the left menu for your app, select **Custom domains**. +1. Select **Add custom domain**. -## Map App Service domain to your app + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-custom-domain.png" alt-text="A screenshot showing how to open the Add custom domain dialog." border="true"::: -It's easy to map a hostname in your App Service domain to an App Service app, as long as it's in the same subscription. You map the App Service domain or any of its subdomain directly in your app, and Azure creates the necessary DNS records for you. +1. For **Domain provider**, select **App Service Domain**. -> [!NOTE] -> If the domain and the app are in different subscriptions, you map the App Service domain to the app just like [mapping an externally purchased domain](app-service-web-tutorial-custom-domain.md). In this case, Azure DNS is the external domain provider, and you need to [add the required DNS records manually](#manage-custom-dns-records). -> +1. For **TLS/SSL certificate**, select **App Service Managed Certificate** if your app is in **Basic** tier or higher. If you want to remain in **Shared** tier, or if you want to use your own certificate, select **Add certificate later**. -### Map the domain +1. For **TLS/SSL type**, select the binding type you want. -1. In the left navigation of the app page, scroll to the **Settings** section and select **Custom domains**. + [!INCLUDE [Certificate binding types](../../includes/app-service-ssl-binding-types.md)] -  +1. In **App Service Domain**, select an App Service domain in your subscription. -1. Select **Add custom domain**. + > [!NOTE] + > To map from an App Service domain in a different subscription, see [Map an externally purchased domain](app-service-web-tutorial-custom-domain.md). In this case, Azure DNS is the external domain provider, and you need to add the required DNS records manually. + > -  +1. In **Domain type**, configure the domain type you want to map: -1. Type the App Service domain (such as **contoso.com**) or a subdomain (such as **www.contoso.com**) and click **Validate**. + | Domain type | Description | + | -- | -- | + | **Root domain** | The root or apex subdomain. If you buy the `contoso.com` domain, then it's the root domain. | + | **Subdomain** | In the **Subdomain** textbox, specify a subdomain like `www` or `shoppingcart`. | - > [!NOTE] - > If you made a typo in the App Service domain name, a verification error appears at the bottom of the page to tell you that you're missing some DNS records. You don't need to add these records manually for an App Service domain. Just make sure that you type the domain name correctly and click **Validate** again. - > - >  +1. Select **Add**. -1. Accept the **Hostname record type** and click **Add custom domain**. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/map-app-service-domain-to-app.png" alt-text="A screenshot showing how to map an App Service domain in the Add custom domain dialog." border="true"::: -  +1. You should see the custom domain added to the list. You may also see a red X with **No binding**. -1. It might take some time for the new custom domain to be reflected in the app's **Custom Domains** page. Refresh the browser to update the data. + If you selected **App Service Managed Certificate** earlier, wait a few minutes for App Service to create the managed certificate for your custom domain. When the process is complete, the red X becomes a green check mark with **Secured**. If you selected **Add certificate later**, this red X will remain until you [add a private certificate for the domain](configure-ssl-certificate.md) and [configure the binding](configure-ssl-bindings.md). -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-app-service-domain-hostname-complete.png" alt-text="A screenshot showing the custom domains page with the new secured custom domain." border="true"::: > [!NOTE]- > A **Not Secure** label for your custom domain means that it's not yet bound to a TLS/SSL certificate. Any HTTPS request from a browser to your custom domain will receive an error or warning, depending on the browser. To add a TLS binding, see [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md). - -### Test the custom domain + > Unless you configure a certificate binding for your custom domain, Any HTTPS request from a browser to the domain will receive an error or warning, depending on the browser. -To test the custom domain, navigate to it in the browser. +1. Test the mapping by navigating to it (like `shoppingcart.contoso.com`) in the browser. ## Renew the domain -The App Service domain you bought is valid for one year from the time of purchase. You can configure to renew your domain automatically which will charge your payment method when your domain renews the following year. You can also manually renew your domain name. +The App Service domain you bought is valid for one year from the time of purchase. You can configure to renew your domain automatically, which will charge your payment method when your domain renews the following year. You can also manually renew your domain name. If you want to configure automatic renewal, or if you want to manually renew your domain, follow the steps here. 1. In the search bar, search for and select **App Service Domains**. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/view-app-service-domains.png" alt-text="A screenshot showing how to open the App Service domain view." border="true"::: -1. In the **App Service Domains** section, select the domain you want to configure. +1. Select the domain you want to configure. 1. From the left navigation of the domain, select **Domain renewal**. To start renewing your domain automatically, select **On**, otherwise select **Off**. The setting takes effect immediately. If automatic renewal is enabled, on the day after your domain expiration date, Azure attempts to bill you for the domain name renewal. -  + :::image type="content" source="./media/custom-dns-web-site-buydomains-web-app/dncmntask-cname-buydomains-autorenew.png" alt-text="Screenshot that shows the option to automatically renew your domain." border="true"::: > [!NOTE]- > When navigating away from the page, disregard the "Your unsaved edits will be discarded" error by clicking **OK**. + > When navigating away from the page, disregard the "Your unsaved edits will be discarded" error by selecting **OK**. > -To manually renew your domain, select **Renew domain**. However, this button is not active until 90 days before the domain's expiration date. +To manually renew your domain, select **Renew domain**. However, this button isn't active until 90 days before the domain's expiration date. If your domain renewal is successful, you receive an email notification within 24 hours. In Azure, DNS records for an App Service Domain are managed using [Azure DNS](ht 1. In the search bar, search for and select **App Service Domains**. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/view-app-service-domains.png" alt-text="A screenshot showing how to open the App Service domain view in the manage custom DNS records section." border="true"::: -1. In the **App Service Domains** section, select the domain you want to configure. +1. Select the domain you want to configure. 1. From the **Overview** page, select **Manage DNS records**. For information on how to edit DNS records, see [How to manage DNS Zones in the ## Cancel purchase (delete domain) -After you purchase the App Service Domain, you have five days to cancel your purchase for a full refund. After five days, you can delete the App Service Domain, but cannot receive a refund. +After you purchase the App Service Domain, you have five days to cancel your purchase for a full refund. After five days, you can delete the App Service Domain, but can't receive a refund. 1. In the search bar, search for and select **App Service Domains**. -  + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/view-app-service-domains.png" alt-text="A screenshot showing how to open the App Service domain view in the manage custom DNS records section." border="true"::: -1. In the **App Service Domains** section, select the domain you want to configure. +1. Select the domain you want to configure. 1. In the domain's left navigation, select **Locks**. A delete lock has been created for your domain. As long as a delete lock exists, you can't delete the App Service domain. -1. Click **Delete** to remove the lock. +1. Select **Delete** to remove the lock. 1. In the domain's left navigation, select **Overview**. -1. If the cancellation period on the purchased domain has not elapsed, select **Cancel purchase**. Otherwise, you see a **Delete** button instead. To delete the domain without a refund, select **Delete**. +1. If the cancellation period on the purchased domain hasn't elapsed, select **Cancel purchase**. Otherwise, you see a **Delete** button instead. To delete the domain without a refund, select **Delete**. -  + :::image type="content" source="./media/custom-dns-web-site-buydomains-web-app/dncmntask-cname-buydomains-cancel.png" alt-text="Screenshot that shows where to delete or cancel a purchased domain." border="true"::: 1. Confirm the operation by selecting **Yes**. After the operation is complete, the domain is released from your subscription and available for anyone to purchase again. -## Direct default URL to a custom directory +## Frequently asked questions ++- [Why do I see "This subscription does not have the billing support to purchase an App Service domain"?](#why-do-i-see-this-subscription-does-not-have-the-billing-support-to-purchase-an-app-service-domain) +- [Why do I get a SubscriptionExceededMaxDomainLimit error when creating an App Service domain?](#why-do-i-get-a-subscriptionexceededmaxdomainlimit-error-when-creating-an-app-service-domain) +- [How do I direct the default URL to a custom directory?](#how-do-i-direct-the-default-url-to-a-custom-directory) ++#### Why do I see "This subscription does not have the billing support to purchase an App Service domain"? ++Free subscriptions, which don't require a confirmed credit card, do not have the permissions to buy App Service domains in Azure. ++#### Why do I get a SubscriptionExceededMaxDomainLimit error when creating an App Service domain? ++The number of App Service domains a subscription can have depends on the subscription type. Subscriptions that have a monthly credit allotment, like Visual Studio Enterprise Subscription, have a limit of 1 App Service domain. To increase your limit, convert to a pay-per-use subscription. ++#### How do I direct the default URL to a custom directory? -By default, App Service directs web requests to the root directory of your app code. To direct them to a subdirectory, such as `public`, see [Redirect to a custom directory](configure-common.md#redirect-to-a-custom-directory). +This is not a DNS resolution scenario. By default, App Service directs web requests to the root directory of your app code. To direct them to a subdirectory, such as `public`, see [Redirect to a custom directory](configure-common.md#redirect-to-a-custom-directory). ## Next steps |
app-service | Manage Custom Dns Migrate Domain | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/manage-custom-dns-migrate-domain.md | tags: top-support-issue ms.assetid: 10da5b8a-1823-41a3-a2ff-a0717c2b5c2d Previously updated : 08/25/2020 Last updated : 01/31/2023 If you're not worried about downtime in DNS resolution, see [Map an existing cus ## Prerequisites -To complete this how-to, [make sure that your App Service app is not in FREE tier](manage-scale-up.md#scale-up-your-pricing-tier). +To complete the steps, [make sure that your App Service app isn't in FREE tier](manage-scale-up.md#scale-up-your-pricing-tier). -## Bind the domain name preemptively +## 1. Get a domain verification ID When you bind a custom domain preemptively, you accomplish both of the following before making any changes to your existing DNS records: -- Verify domain ownership-- Enable the domain name for your app+- Verify domain ownership by adding a domain verification ID with your domain provider. +- Enable the domain name in your App service app. When you finally migrate your custom DNS name from the old site to the App Service app, there will be no downtime in DNS resolution. +1. In the [Azure portal](https://portal.azure.com), open the management page of the App Service app. -### Get domain verification ID +1. In the left pane of your app page, select **Custom domains**. +1. Copy the ID in the **Custom Domain Verification ID** box in the **Custom Domains** page for the next steps. -Get the domain verification ID for you app by following the steps at [Get domain verification ID](app-service-web-tutorial-custom-domain.md#2-get-a-domain-verification-id). + :::image type="content" source="./media/manage-custom-dns-migrate-domain/get-domain-verification-id.png" alt-text="Screenshot that shows the ID in the Custom Domain Verification ID box." border="true"::: -### Create domain verification record +## 2. Create the DNS records -To verify domain ownership, add a TXT record for domain verification. The hostname for the TXT record depends on the type of DNS record type you want to map. See the following table (`@` typically represents the root domain): ++Add a TXT record for domain verification. The hostname for the TXT record depends on the type of DNS record type you want to map. See the following table (`@` typically represents the root domain): | DNS record example | TXT Host | TXT Value | | - | - | - |-| \@ (root) | _asuid_ | [Domain verification ID for your app](app-service-web-tutorial-custom-domain.md#2-get-a-domain-verification-id) | -| www (sub) | _asuid.www_ | [Domain verification ID for your app](app-service-web-tutorial-custom-domain.md#2-get-a-domain-verification-id) | -| \* (wildcard) | _asuid_ | [Domain verification ID for your app](app-service-web-tutorial-custom-domain.md#2-get-a-domain-verification-id) | --In your DNS records page, note the record type of the DNS name you want to migrate. App Service supports mappings from CNAME and A records. +| \@ (root) | _asuid_ | Domain verification ID shown in the **Custom domains** management page. | +| www (sub) | _asuid.www_ | Domain verification ID shown in the **Custom domains** management page. | +| \* (wildcard) | _asuid_ | Domain verification ID shown in the **Custom domains** management page. | > [!NOTE] > Wildcard `*` records won't validate subdomains with an existing CNAME's record. You may need to explicitly create a TXT record for each subdomain.+ +## 3. Enable the domain for your app -### Enable the domain for your app +1. Back in the **Custom domains** page, select **Add custom domain**. -1. In the [Azure portal](https://portal.azure.com), in the left navigation of the app page, select **Custom domains**. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-custom-domain.png" alt-text="A screenshot showing how to open the Add custom domain dialog." border="true"::: -  +1. For **Domain provider**, select **All other domain services** to configure a third-party domain. -1. In the **Custom domains** page, select **Add custom domain**. +1. For **TLS/SSL certificate**, select **Add certificate later**. You can add an App Service managed certificate after you have completed domain migration. -  +1. For **TLS/SSL type**, select the binding type you want. -1. Type the fully qualified domain name you want to migrate, that corresponds to the TXT record you create, such as `contoso.com`, `www.contoso.com`, or `*.contoso.com`. Select **Validate**. + [!INCLUDE [Certificate binding types](../../includes/app-service-ssl-binding-types.md)] - The **Add custom domain** button is activated. +1. Type the fully qualified domain name you want to migrate, that corresponds to the TXT record you created, such as `contoso.com`, `www.contoso.com`, or `*.contoso.com`. -1. Make sure that **Hostname record type** is set to the DNS record type you want to migrate. Select **Add hostname**. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/configure-custom-domain-preempt.png" alt-text="A screenshot showing how to configure a new custom domain, along with a managed certificate." border="true"::: -  +1. Select **Validate**. Although the dialog shows two records you need for the custom domain to be functional for your app, the validation passes with just the domain verification ID (the TXT record). - It might take some time for the new hostname to be reflected in the app's **Custom domains** page. Try refreshing the browser to update the data. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/configure-custom-domain-validate.png" alt-text="A screenshot showing how to validate your DNS record settings in the Add a custom domain dialog." border="true"::: -  +1. If the **Domain validation** section shows green check marks, then you've configured the domain verification ID correctly. Select **Add**. If it shows any red X, fix any errors in your domain provider's website. - Your custom DNS name is now enabled in your Azure app. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/configure-custom-domain-preempt-add.png" alt-text="A screenshot showing the Add button activated after validation." border="true"::: -## Remap the active DNS name +1. You should see the custom domain added to the list. You may also see a red X with **No binding**. -The only thing left to do is remapping your active DNS record to point to App Service. Right now, it still points to your old site. + Since you selected **Add certificate later**, you see a red X with **No binding**. It will remain until you [add a private certificate for the domain](configure-ssl-certificate.md) and [configure the binding](configure-ssl-bindings.md). + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/add-custom-domain-preempt-complete.png" alt-text="A screenshot showing the custom domains page with the new secured custom domain." border="true"::: ++ > [!NOTE] + > Unless you configure a certificate binding for your custom domain, Any HTTPS request from a browser to the domain will receive an error or warning, depending on the browser. + <a name="info"></a> -### Copy the app's IP address (A record only) +## 4. Remap the active DNS name -If you are remapping a CNAME record, skip this section. +The only thing left to do is remapping your active DNS record to point to App Service. Right now, it still points to your old site. -To remap an A record, you need the App Service app's external IP address, which is shown in the **Custom domains** page. +1. **(A record only)** You need the App Service app's external IP address. In the **Custom domains** page, copy the app's IP address. -In the **Custom domains** page, copy the app's IP address. + :::image type="content" source="./media/app-service-web-tutorial-custom-domain/mapping-information-migrate.png" alt-text="A screenshot showing how to copy the App Service app's external IP address." border="true"::: - +1. Back in the DNS records page of your domain provider, select the DNS record to remap. -### Update the DNS record +1. Remap the A or CNAME record like the examples in the following table: + + | FQDN example | Record type | Host | Value | + | - | - | - | - | + | contoso.com (root) | A | `@` | IP address from [Copy the app's IP address](#info) | + | www\.contoso.com (sub) | CNAME | `www` | _<app-name>.azurewebsites.net_ | + | \*.contoso.com (wildcard) | CNAME | _\*_ | _<app-name>.azurewebsites.net_ | + +1. Save your settings. -Back in the DNS records page of your domain provider, select the DNS record to remap. +DNS queries should start resolving to your App Service app immediately after DNS propagation happens. -For the `contoso.com` root domain example, remap the A or CNAME record like the examples in the following table: +## Frequently asked questions -| FQDN example | Record type | Host | Value | -| - | - | - | - | -| contoso.com (root) | A | `@` | IP address from [Copy the app's IP address](#info) | -| www\.contoso.com (sub) | CNAME | `www` | _<appname>.azurewebsites.net_ | -| \*.contoso.com (wildcard) | CNAME | _\*_ | _<appname>.azurewebsites.net_ | +- [Can I add an App Service managed certificate when migrating a live domain?](#can-i-add-an-app-service-managed-certificate-when-migrating-a-live-domain) +- [How do I migrate a domain from another app?](#how-do-i-migrate-a-domain-from-another-app) -Save your settings. +#### Can I add an App Service managed certificate when migrating a live domain? -DNS queries should start resolving to your App Service app immediately after DNS propagation happens. +You can add an App Service managed certificate to a migrated live domain, but only after you [remap the active DNS name](#4-remap-the-active-dns-name). To add the App Service managed certificate, see [Create a free managed certificate](configure-ssl-certificate.md#create-a-free-managed-certificate). -## Migrate domain from another app +#### How do I migrate a domain from another app? -You can migrate an active custom domain in Azure, between subscriptions or within the same subscription. However, such a migration without downtime requires the source app and the target app are assigned the same custom domain at a certain time. Therefore, you need to make sure that the two apps are not deployed to the same deployment unit (internally known as a webspace). A domain name can be assigned to only one app in each deployment unit. +You can migrate an active custom domain in Azure, between subscriptions or within the same subscription. However, such a migration without downtime requires the source app and the target app are assigned the same custom domain at a certain time. Therefore, you need to make sure that the two apps aren't deployed to the same deployment unit (internally known as a webspace). A domain name can be assigned to only one app in each deployment unit. -You can find the deployment unit for your app by looking at the domain name of the FTP/S URL `<deployment-unit>.ftp.azurewebsites.windows.net`. Check and make sure the deployment unit is different between the source app and the target app. The deployment unit of an app is determined by the [App Service plan](overview-hosting-plans.md) it's in. It's selected randomly by Azure when you create the plan and can't be changed. Azure only makes sure two plans are in the same deployment unit when you [create them in the same resource group *and* the same region](app-service-plan-manage.md#create-an-app-service-plan), but it doesn't have any logic to make sure plans are in different deployment units. The only way for you to create a plan in a different deployment unit is to keep creating a plan in a new resource group or region until you get a different deployment unit. +You can find the deployment unit for your app by looking at the domain name of the FTP/S URL `<deployment-unit>.ftp.azurewebsites.windows.net`. Check and make sure the deployment unit is different between the source app and the target app. The deployment unit of an app is determined by the [App Service plan](overview-hosting-plans.md) it's in. It's selected randomly by Azure when you create the plan and can't be changed. When you create two apps [in the same resource group *and* the same region](app-service-plan-manage.md#create-an-app-service-plan), Azure puts them in the same deployment unit. However, there's no way to make sure that the opposite is true. In other words, the only way to create a plan in a different deployment unit is to keep creating a plan in a new resource group or region until you get a different deployment unit. ## Next steps Learn how to bind a custom TLS/SSL certificate to App Service. +> [!div class="nextstepaction"] +> [Purchase an App Service domain](manage-custom-dns-buy-domain.md). + > [!div class="nextstepaction"] > [Secure a custom DNS name with a TLS binding in Azure App Service](configure-ssl-bindings.md) |
app-service | Manage Disaster Recovery | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/manage-disaster-recovery.md | Certain resources, such as imported certificates or hybrid connections, contain 3. Configure [everything else](#prepare) in the target app to mirror the impacted app and verify your configuration. -4. When you're ready for the custom domain to point to the target app, [remap the domain name](manage-custom-dns-migrate-domain.md#remap-the-active-dns-name). +4. When you're ready for the custom domain to point to the target app, [remap the domain name](manage-custom-dns-migrate-domain.md#4-remap-the-active-dns-name). ## Recover app content only |
app-service | Manage Move Across Regions | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/manage-move-across-regions.md | Certain resources, such as imported certificates or hybrid connections, contain 1. [Create a back up of the source app](manage-backup.md). 1. [Create an app in a new App Service plan, in the target region](app-service-plan-manage.md#create-an-app-service-plan). 2. [Restore the back up in the target app](manage-backup.md)-2. If you use a custom domain, [bind it preemptively to the target app](manage-custom-dns-migrate-domain.md#bind-the-domain-name-preemptively) with `asuid.` and [enable the domain in the target app](manage-custom-dns-migrate-domain.md#enable-the-domain-for-your-app). +2. If you use a custom domain, [bind it preemptively to the target app](manage-custom-dns-migrate-domain.md#2-create-the-dns-records) with `asuid.` and [enable the domain in the target app](manage-custom-dns-migrate-domain.md#3-enable-the-domain-for-your-app). 3. Configure everything else in your target app to be the same as the source app and verify your configuration.-4. When you're ready for the custom domain to point to the target app, [remap the domain name](manage-custom-dns-migrate-domain.md#remap-the-active-dns-name). +4. When you're ready for the custom domain to point to the target app, [remap the domain name](manage-custom-dns-migrate-domain.md#4-remap-the-active-dns-name). <!-- 1. Login to the [Azure portal](https://portal.azure.com) > **Resource Groups**. 2. Locate the Resource Group that contains the source App Service resources and click on it. |
app-service | Quickstart Arm Template | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-arm-template.md | When no longer needed, [delete the resource group](../azure-resource-manager/man > [Connect to Azure SQL database with Java](/azure/azure-sql/database/connect-query-java?toc=%2fazure%2fjava%2ftoc.json) > [!div class="nextstepaction"]-> [Map custom domain](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Dotnetcore Uiex | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-dotnetcore-uiex.md | If you've installed Visual Studio 2019 already: 1. In **Solution Explorer**, right-click the **myFirstAzureWebApp** project and select **Publish**. -1. In **Publish**, select **Azure** and click **Next**. +1. In **Publish**, select **Azure** and select **Next**. 1. Your options depend on whether you're signed in to Azure already and whether you have a Visual Studio account linked to an Azure account. Select either **Add an account** or **Sign in** to sign in to your Azure subscription. If you're already signed in, select the account you want.  -1. To the right of **App Service instances**, click **+**. +1. To the right of **App Service instances**, select **+**.  If you've installed Visual Studio 2019 already: 1. Wait for the wizard to finish creating Azure resources. Select **Finish** to close the wizard. -1. In the **Publish** page, click **Publish** to deploy your project. +1. In the **Publish** page, select **Publish** to deploy your project. <details> <summary>What's Visual Studio doing?</summary> http://<app_name>.azurewebsites.net <details> <summary>What's <code>az webapp up</code> doing this time?</summary>- The first time you ran the command, it saved the app name, resource group, and App Service plan in the <i>.azure/config</i> file from the project root. When you run it again from the project root, it uses the values saved in <i>.azure/config</i>, detects that the App Service resources already exists, and performs Zip deploy again. + The first time you ran the command, it saved the app name, resource group, and App Service plan in the <i>.azure/config</i> file from the project root. When you run it again from the project root, it uses the values saved in <i>.azure/config</i>, detects that the App Service resources already exist, and performs Zip deploy again. </details> 1. Once deployment has completed, **hit refresh** in the browser window that previously opened. http://<app_name>.azurewebsites.net 1. Go to the <a href="https://portal.azure.com" target="_blank">Azure portal</a>. -1. From the left menu, click **App Services**, and then click the name of your Azure app. +1. From the left menu, select **App Services**, and then select the name of your Azure app. :::image type="content" source="./media/quickstart-dotnetcore/portal-app-service-list-up.png" alt-text="Screenshot of the App Services page showing an example Azure app selected."::: az group delete --name myResourceGroup - [Tutorial: ASP.NET Core app with SQL Database](tutorial-dotnetcore-sqldb-app.md) - [Configure ASP.NET Core app](configure-language-dotnetcore.md)+- [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) ::: zone-end |
app-service | Quickstart Dotnetcore | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-dotnetcore.md | Advance to the next article to learn how to create a .NET Framework app and conn > [!div class="nextstepaction"] > [Configure ASP.NET Framework app](configure-language-dotnet-framework.md) +> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) + [app-service-pricing-tier]: https://azure.microsoft.com/pricing/details/app-service/?ref=microsoft.com&utm_source=microsoft.com&utm_medium=docs&utm_campaign=visualstudio |
app-service | Quickstart Golang | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-golang.md | az group delete --resource-group <resource-group-name> > [Tutorial: Deploy from Azure Container Registry](./tutorial-custom-container.md) > [!div class="nextstepaction"]-> [Tutorial: Map a custom domain name](./app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Html Uiex | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-html-uiex.md | This command may take a minute to run. ## Next steps > [!div class="nextstepaction"]-> Map custom domain +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Html | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-html.md | This command may take a minute to run. ## Next steps > [!div class="nextstepaction"]-> [Map custom domain](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Java Uiex | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-java-uiex.md | This command may take a minute to run. > [!div class="nextstepaction"] > [Configure your Java app](configure-language-java.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Java | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-java.md | adobe-target-content: ./quickstart-java-uiex > [!div class="nextstepaction"] > [Configure your Java app](configure-language-java.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Multi Container | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-multi-container.md | Browse to the deployed app at (`http://<app_name>.azurewebsites.net`). The app m > [!div class="nextstepaction"] > [Configure a custom container](configure-custom-container.md) +> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) + <!--Image references--> [1]: media/tutorial-multi-container-app/azure-multi-container-wordpress-install.png |
app-service | Quickstart Nodejs | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-nodejs.md | This quickstart configures an App Service app in the **Free** tier and incurs no - Have an Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?utm_source=campaign&utm_campaign=vscode-tutorial-app-service-extension&mktingSource=vscode-tutorial-app-service-extension). - Install [Node.js LTS and npm](https://nodejs.org). Run the command `node --version` to verify that Node.js is installed.-- Install <a href="/cli/azure/install-azure-cli" target="_blank">Azure CLI</a>, with which you run commands in any shell to provision and configure Azure resources.+- Install <a href="/cli/azure/install-azure-cli" target="_blank">Azure CLI</a>, with which you run commands in any shell to create and configure Azure resources. ::: zone-end This quickstart configures an App Service app in the **Free** tier and incurs no - Have an Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?utm_source=campaign&utm_campaign=vscode-tutorial-app-service-extension&mktingSource=vscode-tutorial-app-service-extension). - Install [Node.js LTS and npm](https://nodejs.org). Run the command `node --version` to verify that Node.js is installed.-- Have a FTP client (for example, [FileZilla](https://filezilla-project.org)), to connect to your app.+- Have an FTP client (for example, [FileZilla](https://filezilla-project.org)), to connect to your app. ::: zone-end ## Create your Node.js application Before you continue, ensure that you have all the prerequisites installed and co 2. Right-click on App Services and select **Create new Web App**. A Linux container is used by default. 1. Type a globally unique name for your web app and press **Enter**. The name must be unique across all of Azure and use only alphanumeric characters ('A-Z', 'a-z', and '0-9') and hyphens ('-'). 1. In Select a runtime stack, select the Node.js version you want. An **LTS** version is recommended.-1. In Select a pricing tier, select **Free (F1)** and wait for the resources to be provisioned in Azure. +1. In Select a pricing tier, select **Free (F1)** and wait for the resources to be created in Azure. 1. In the popup **Always deploy the workspace "myExpressApp" to \<app-name>"**, select **Yes**. This way, as long as you're in the same workspace, Visual Studio Code deploys to the same App Service app each time. - While Visual Studio Code provisions the Azure resources and deploys the code, it shows [progress notifications](https://code.visualstudio.com/api/references/extension-guidelines#notifications). + While Visual Studio Code creates the Azure resources and deploys the code, it shows [progress notifications](https://code.visualstudio.com/api/references/extension-guidelines#notifications). 1. Once deployment completes, select **Browse Website** in the notification popup. The browser should display the Express default page. Before you continue, ensure that you have all the prerequisites installed and co 1. Select **Windows** for the operating system. 1. Select the location you want to serve your app from. For example, *West Europe*. 1. Select **Create new App Service plan**, then enter a name for the plan (such as *AppServiceQS-plan*), then select **F1 Free** for the pricing tier.-1. For **Select an Application Insights resource for your app**, select **Skip for now** and wait the resources to be provisioned in Azure. +1. For **Select an Application Insights resource for your app**, select **Skip for now** and wait the resources to be created in Azure. 1. In the popup **Always deploy the workspace "myExpressApp" to \<app-name>"**, select **Yes**. This way, as long as you're in the same workspace, Visual Studio Code deploys to the same App Service app each time. - While Visual Studio Code provisions the Azure resources and deploys the code, it shows [progress notifications](https://code.visualstudio.com/api/references/extension-guidelines#notifications). + While Visual Studio Code creates the Azure resources and deploys the code, it shows [progress notifications](https://code.visualstudio.com/api/references/extension-guidelines#notifications). > [!NOTE] > When deployment completes, your Azure app doesn't run yet because your project root doesn't have a *web.config*. Follow the remaining steps to generate it automatically. For more information, see [You do not have permission to view this directory or page](configure-language-nodejs.md#you-do-not-have-permission-to-view-this-directory-or-page). Congratulations, you've successfully completed this quickstart! > [!div class="nextstepaction"] > [Configure Node.js app](configure-language-nodejs.md) +> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) + Check out the other Azure extensions. * [Azure Cosmos DB](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-cosmosdb) |
app-service | Quickstart Php | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-php.md | This command may take a minute to run. > [!div class="nextstepaction"] > [Configure PHP app](configure-language-php.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Python 1 | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-python-1.md | The `--no-wait` argument allows the command to return before the operation is co > [!div class="nextstepaction"] > [Tutorial: Run Python app in custom container](tutorial-custom-container.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Python Portal | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-python-portal.md | Having issues? [Let us know](https://aka.ms/FlaskCLIQuickstartHelp). > [Add user sign-in to a Python web app](../active-directory/develop/quickstart-v2-python-webapp.md) > [!div class="nextstepaction"]-> [Tutorial: Run Python app in custom container](tutorial-custom-container.md) +> [Tutorial: Run Python app in custom container](tutorial-custom-container.md) ++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Python | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-python.md | Having issues? [Let us know](https://aka.ms/PythonAppServiceQuickstartFeedback). > [!div class="nextstepaction"] > [Tutorial: Run Python app in custom container](./tutorial-custom-container.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Ruby | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-ruby.md | Your web app's **Overview** page will be displayed. Here, you can perform basic > [!div class="nextstepaction"] > [Configure Ruby app](configure-language-ruby.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Quickstart Wordpress | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/quickstart-wordpress.md | There's a couple approaches when migrating your WordPress app to App Service on Congratulations, you've successfully completed this quickstart! > [!div class="nextstepaction"]-> [Tutorial: Map a custom domain name](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) > [!div class="nextstepaction"] > [Tutorial: PHP app with MySQL](tutorial-php-mysql-app.md) |
app-service | Reference Dangling Subdomain Prevention | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/reference-dangling-subdomain-prevention.md | These records prevent the creation of another App Service app using the same nam DNS records should be updated before the site deletion to ensure bad actors can't take over the domain between the period of deletion and re-creation. -To get a domain verification ID, see the [Map a custom domain tutorial](app-service-web-tutorial-custom-domain.md#2-get-a-domain-verification-id) +To get a domain verification ID, see the [Map a custom domain tutorial](app-service-web-tutorial-custom-domain.md) |
app-service | Troubleshoot Domain Ssl Certificates | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/troubleshoot-domain-ssl-certificates.md | Your configured custom domain is missing a "CNAME record" or an "A record". **Solution for cause 1** -- If you added an "A record", make sure that a TXT record is also added. For more information, see [Create the "A record"](./app-service-web-tutorial-custom-domain.md#3-create-the-dns-records).+- If you added an "A record", make sure that a TXT record is also added. For more information, see [Create the DNS records](./app-service-web-tutorial-custom-domain.md#2-create-the-dns-records). - If you don't have to use the root domain for your app, the recommendation is that you use a "CNAME record", rather than an "A record". |
app-service | Tutorial Auth Aad | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-auth-aad.md | What you learned: Advance to the next tutorial to learn how to map a custom DNS name to your app. > [!div class="nextstepaction"]-> [Map an existing custom DNS name to Azure App Service](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Tutorial Connect Msi Sql Database | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-connect-msi-sql-database.md | What you learned: > * Connect to SQL Database from Visual Studio using Azure AD authentication > [!div class="nextstepaction"]-> [Map an existing custom DNS name to Azure App Service](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) > [!div class="nextstepaction"] > [Tutorial: Connect to Azure databases from App Service without secrets using a managed identity](tutorial-connect-msi-azure-database.md) |
app-service | Tutorial Custom Container | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-custom-container.md | What you learned: ::: zone-end -In the next tutorial, you learn how to map a custom DNS name to your app. +In the next tutorial, you learn how to secure your app with a custom domain and certificate. > [!div class="nextstepaction"]-> [Tutorial: Map custom DNS name to your app](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) Or, check out other resources: |
app-service | Tutorial Dotnetcore Sqldb App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-dotnetcore-sqldb-app.md | git push origin main ## Next steps -Advance to the next tutorial to learn how to map a custom DNS name to your app. +Advance to the next tutorial to learn how to secure your app with a custom domain and certificate. > [!div class="nextstepaction"]-> [Tutorial: Map custom DNS name to your app](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) Or, check out other resources: |
app-service | Tutorial Java Quarkus Postgresql App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-java-quarkus-postgresql-app.md | Learn more about running Java apps on App Service on Linux in the developer guid > [!div class="nextstepaction"] > [Java in App Service Linux dev guide](configure-language-java.md?pivots=platform-linux)++Learn how to secure your app with a custom domain and certificate. ++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Tutorial Java Spring Cosmosdb | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-java-spring-cosmosdb.md | Learn more about running Java apps on App Service on Linux in the developer guid > [!div class="nextstepaction"] > [Java in App Service Linux dev guide](configure-language-java.md?pivots=platform-linux)++Learn how to secure your app with a custom domain and certificate. ++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Tutorial Java Tomcat Connect Managed Identity Postgresql Database | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-java-tomcat-connect-managed-identity-postgresql-database.md | Learn more about running Java apps on App Service on Linux in the developer guid > [!div class="nextstepaction"] > [Java in App Service Linux dev guide](configure-language-java.md?pivots=platform-linux)++Learn how to secure your app with a custom domain and certificate. ++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Tutorial Multi Container App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-multi-container-app.md | In this tutorial, you learned how to: > * Connect to Azure Database for MySQL > * Troubleshoot errors -Advance to the next tutorial to learn how to map a custom DNS name to your app. +Advance to the next tutorial to learn how to secure your app with a custom domain and certificate. > [!div class="nextstepaction"]-> [Tutorial: Map custom DNS name to your app](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) Or, check out other resources: |
app-service | Tutorial Nodejs Mongodb App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-nodejs-mongodb-app.md | Most of the time taken by the two-job process is spent uploading and download ar > [!div class="nextstepaction"] > [Configure Node.js app in App Service](./configure-language-nodejs.md)++> [!div class="nextstepaction"] +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) |
app-service | Tutorial Php Mysql App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-php-mysql-app.md | In this tutorial, you learned how to: > * Stream diagnostic logs from Azure > * Manage the app in the Azure portal -Advance to the next tutorial to learn how to map a custom DNS name to the app. +Advance to the next tutorial to learn how to secure your app with a custom domain and certificate. > [!div class="nextstepaction"]-> [Tutorial: Map custom DNS name to your app](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) Or, check out other resources: |
app-service | Tutorial Python Postgresql App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-python-postgresql-app.md | If you encounter any errors related to connecting to the database, check if the ## Next steps -Learn how to map a custom DNS name to your app: +Advance to the next tutorial to learn how to secure your app with a custom domain and certificate. > [!div class="nextstepaction"]-> [Tutorial: Map custom DNS name to your app](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) Learn how App Service runs a Python app: |
app-service | Tutorial Ruby Postgres App | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-ruby-postgres-app.md | In this tutorial, you learned how to: > * Stream diagnostic logs from Azure > * Manage the app in the Azure portal -Advance to the next tutorial to learn how to map a custom DNS name to your app. +Advance to the next tutorial to learn how to secure your app with a custom domain and certificate. > [!div class="nextstepaction"]-> [Tutorial: Map custom DNS name to your app](app-service-web-tutorial-custom-domain.md) +> [Secure with custom domain and certificate](tutorial-secure-domain-certificate.md) Or, check out other resources: |
app-service | Tutorial Secure Domain Certificate | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/app-service/tutorial-secure-domain-certificate.md | + + Title: 'Tutorial: Secure app with a custom domain and certificate' +description: Learn how to secure your brand with App Service using a custom domain and enabling App Service managed certificate. + Last updated : 01/31/2023+++# Tutorial: Secure your Azure App Service app with a custom domain and a managed certificate ++The default domain name that comes with your app `<app-name>.azurewebsites.net` may not represent your brand the way you want. In this tutorial, you configure App Service with a `www` domain you own, such as `www.contoso.com`, and secure the custom domain with an App Service managed certificate. ++The `<app-name>.azurewebsites.net` name is already secured by a wildcard certificate for all App Service apps, but your custom domain needs to be TLS secured with a separate certificate. The easiest way is to use a managed certificate from App Service. It's free and easy to use, and it provides the basic functionality of securing a custom domain in App Service. For more information, see [Add a TLS certificate to App Service](configure-ssl-certificate.md). ++## Scenario prerequisites ++* [Create an App Service app](./index.yml). +* Make sure you can edit the DNS records for your custom domain. To edit DNS records, you need access to the DNS registry for your domain provider, such as GoDaddy. For example, to add DNS entries for `www.contoso.com`, you must be able to configure the DNS settings for the `contoso.com` root domain. Your custom domains must be in a public DNS zone; private DNS zone is only supported on Internal Load Balancer (ILB) App Service Environment (ASE). +* If you don't have a custom domain yet, you can [purchase an App Service domain](manage-custom-dns-buy-domain.md). ++## A. Scale up your app ++You need to scale your app up to **Basic** tier. **Basic** tier fulfills the minimum pricing tier requirement for custom domains (**Shared**) and certificates (**Basic**). ++ :::column span="2"::: + **Step 1.** In the Azure portal: + 1. Enter the name of your app in the search bar at the top. + 1. Select your named resource with the type **App Service**. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/search-select-app.png" alt-text="A screenshot showing how to use the search box in the top tool bar to open your App Service app's management page." lightbox="./media/tutorial-secure-domain-certificate/search-select-app.png" border="true"::: + :::column-end::: + :::column span="2"::: + **Step 2.** In your app's management page: + 1. In the left navigation, select **Scale up (App Service plan)**. + 1. Select the checkbox for **Basic B1**. + 1. Select **Select**. + When the app update is complete, you see a notification toast. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/scale-up-tier.png" alt-text="A screenshot showing how to scale up an App Service app to Basic B1 tier." lightbox="./media/tutorial-secure-domain-certificate/scale-up-tier.png" border="true"::: + :::column-end::: ++For more information on app scaling, see [Scale up an app in Azure App Service](manage-scale-up.md). ++## B. Configure a custom domain ++ :::column span="2"::: + **Step 1.** In your app's management page: + 1. In the left menu, select **Custom domains**. + 1. Select **Add custom domain**. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/add-custom-domain.png" alt-text="A screenshot showing how to add a custom domain." lightbox="./media/tutorial-secure-domain-certificate/add-custom-domain.png" border="true"::: + :::column-end::: + :::column span="2"::: + **Step 2.** In the **Add custom domain** dialog: + 1. For **Domain provider**, select **All other domain services**. + 1. For **TLS/SSL certificate**, select **App Service Managed Certificate**. + 1. For Domain, specify a fully qualified domain name you want based on the domain you own. For example, if you own `contoso.com`, you can use *www.contoso.com*. + 1. Don't select **Validate** yet. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/configure-custom-domain.png" alt-text="A screenshot showing how to configure a new custom domain, along with a managed certificate." lightbox="./media/tutorial-secure-domain-certificate/add-custom-domain.png" border="true"::: + :::column-end::: ++For each custom domain in App Service, you need two DNS records with your domain provider. The **Domain validation** section shows you two DNS records that you must add with your domain provider. Select the respective **Copy** button to help you with the next step. ++## C. Create the DNS records ++ :::column span="2"::: + Sign in to the website of your domain provider. + 1. Find the page for managing DNS records, **Domain Name**, **DNS**, or **Name Server Management** (the exact page differs by domain provider). + 1. Select **Add** or the appropriate widget to create a DNS record. + 1. Select the DNS record type based on the **Domain validation** section in the Azure portal (CNAME, A, or TXT). + 1. Configure the DNS record based on the **Host** and **Value** columns from the **Domain validation** section in the Azure portal. + 1. Be sure to add two different records for your custom domain. + 1. For certain providers, changes to DNS records don't become effective until you select a separate **Save Changes** link. + The screenshot shows what your DNS records should look like for a `www` subdomain after you're finished. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/cname-record.png" alt-text="A screenshot showing an example of what your domain provider's website should look like after you add a CNAME record and a TXT record for a www subdomain." lightbox="./media/tutorial-secure-domain-certificate/cname-record.png" border="true"::: + :::column-end::: ++## D. Validate and complete ++ :::column span="2"::: + **Step 1.** Back in the **Add custom domain** dialog in the Azure portal, select **Validate**. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/configure-custom-domain-validate.png" alt-text="A screenshot showing how to validate your DNS record settings in the Add a custom domain dialog." lightbox="./media/tutorial-secure-domain-certificate/configure-custom-domain-validate.png" border="true"::: + :::column-end::: + :::column span="2"::: + **Step 2.** If the **Domain validation** section shows green check marks next for both domain records, then you've configured them correctly. Select **Add**. If it shows any red X, fix any errors in the DNS record settings in your domain provider's website. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/configure-custom-domain-add.png" alt-text="A screenshot showing the Add button activated after validation." lightbox="./media/tutorial-secure-domain-certificate/configure-custom-domain-add.png" border="true"::: + :::column-end::: + :::column span="2"::: + **Step 3.** You should see the custom domain added to the list. You may also see a red X with **No binding**. Wait a few minutes for App Service to create the managed certificate for your custom domain. When the process is complete, the red X becomes a green check mark with **Secured**. + :::column-end::: + :::column::: + :::image type="content" source="./media/tutorial-secure-domain-certificate/add-custom-domain-complete.png" alt-text="A screenshot showing the custom domains page with the new secured custom domain." lightbox="./media/tutorial-secure-domain-certificate/add-custom-domain-complete.png" border="true"::: + :::column-end::: ++## E. Test in a browser ++Browse to the DNS names that you configured earlier (like `www.contoso.com`). The address bar should now show the security lock icon for your app's URL, indicating that it's secured by TLS. +++If you receive an HTTP 404 (Not Found) error when you browse to the URL of your custom domain, the browser client may have cached the old IP address of your custom domain. Clear the cache, and try navigating to the URL again. On a Windows machine, you clear the cache with `ipconfig /flushdns`. ++## Frequently asked questions ++- [What do I do if I don't have a custom domain yet?](#what-do-i-do-if-i-dont-have-a-custom-domain-yet) +- [Does this managed certificate expire?](#does-this-managed-certificate-expire) +- [What else can I do with the App Service managed certificate for my app?](#what-else-can-i-do-with-the-app-service-managed-certificate-for-my-app) +- [How do I use a certificate I already have to secure my custom domain?](#how-do-i-use-a-certificate-i-already-have-to-secure-my-custom-domain) ++#### What do I do if I don't have a custom domain yet? ++The `<app-name>.azurewebsites.net` name is always assigned to your app as long as you don't delete it. If you want, you can [purchase an App Service domain](manage-custom-dns-buy-domain.md). An App Service domain is managed by Azure and is integrated with App Service, making it easier to manage together with your apps. ++#### Does this managed certificate expire? ++The App Service managed certificate doesn't expire as long as it's configured for a custom domain in an App Service app. ++#### What else can I do with the App Service managed certificate for my app? ++The managed certificate is provided for free for the sole purpose of securing your app's configured custom domain. It comes with [a number of limitations](configure-ssl-certificate.md#create-a-free-managed-certificate). To do more, such as download the certificate, or use it in your application code, you can upload your own certificate, purchase an App Service certificate, or import a Key Vault certificate. For more information, see [Add a private certificate to your app](configure-ssl-certificate.md). ++#### How do I use a certificate I already have to secure my custom domain? ++See [Add a private certificate to your app](configure-ssl-certificate.md) and [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md). ++## Next steps ++- [Map an existing custom DNS name to Azure App Service](app-service-web-tutorial-custom-domain.md) +- [Purchase an App Service domain](manage-custom-dns-buy-domain.md) +- [Add a private certificate to your app](configure-ssl-certificate.md) +- [Secure a custom DNS name with a TLS/SSL binding in Azure App Service](configure-ssl-bindings.md) |
application-gateway | Tutorial Protect Application Gateway Ddos | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/application-gateway/tutorial-protect-application-gateway-ddos.md | + + Title: 'Tutorial: Protect your application gateway with Azure DDoS Protection Standard' ++description: Learn how to set up an application gateway and protect it with Azure DDoS protection +++ Last updated : 12/21/2022++++++# Tutorial: Protect your application gateway with Azure DDoS Protection Standard ++This article helps you create an Azure Application Gateway with a DDoS protected virtual network. Azure DDoS Protection Standard enables enhanced DDoS mitigation capabilities such as adaptive tuning, attack alert notifications, and monitoring to protect your application gateways from large scale DDoS attacks. ++> [!IMPORTANT] +> Azure DDoS Protection incurs a cost when you use the Standard SKU. Overages charges only apply if more than 100 public IPs are protected in the tenant. Ensure you delete the resources in this tutorial if you aren't using the resources in the future. For information about pricing, see [Azure DDoS Protection Pricing]( https://azure.microsoft.com/pricing/details/ddos-protection/). For more information about Azure DDoS protection, see [What is Azure DDoS Protection?](../ddos-protection/ddos-protection-overview.md). ++In this tutorial, you learn how to: ++> [!div class="checklist"] +> * Create a DDoS protection plan +> * Create an application gateway +> * Associate a DDoS Protection plan to the virtual network +> * Add VMs to the backend of the application gateway +> * Test the application gateway ++## Prerequisites ++An Azure account with an active subscription is required. If you don't already have an account, you can [create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). ++## Create a DDoS protection plan ++1. Sign in to the [Azure portal](https://portal.azure.com). ++1. In the search box at the top of the portal, enter **DDoS protection**. Select **DDoS protection plans** in the search results and then select **+ Create**. ++1. In the **Basics** tab of **Create a DDoS protection plan** page, enter or select the following information: ++ :::image type="content" source="./media/tutorial-protect-application-gateway/create-ddos-plan.png" alt-text="Screenshot of basics tab for creating a DDoS protection plan."::: ++ | Setting | Value | + |--|--| + | **Project details** | | + | Subscription | Select your Azure subscription. | + | Resource group | Select **Create new**. </br> Enter **myResourceGroupAG**. </br> Select **OK**. | + | **Instance details** | | + | Name | Enter **myDDoSProtectionPlan**. | + | Region | Select **Central US**. | ++1. Select **Review + create** and then select **Create** to deploy the DDoS protection plan. ++## Create an application gateway ++You'll create the application gateway using the tabs on the **Create application gateway** page. ++1. On the Azure portal menu or from the **Home** page, select **Create a resource**. +2. Under **Categories**, select **Networking** and then select **Application Gateway** in the **Popular Azure services** list. ++### Basics tab ++1. On the **Basics** tab, enter these values for the following application gateway settings: ++ - **Resource group**: Select **myResourceGroupAG** for the resource group. If it doesn't exist, select **Create new** to create it. + - **Application gateway name**: Enter *myAppGateway* for the name of the application gateway. ++  ++2. For Azure to communicate between the resources that you create, a virtual network is needed. You can either create a new virtual network or use an existing one. In this example, you'll create a new virtual network at the same time that you create the application gateway. Application Gateway instances are created in separate subnets. You create two subnets in this example: One for the application gateway, and another for the backend servers. ++ > [!NOTE] + > [Virtual network service endpoint policies](../virtual-network/virtual-network-service-endpoint-policies-overview.md) are currently not supported in an Application Gateway subnet. ++ Under **Configure virtual network**, create a new virtual network by selecting **Create new**. In the **Create virtual network** window that opens, enter the following values to create the virtual network and two subnets: ++ - **Name**: Enter *myVNet* for the name of the virtual network. ++ - **Subnet name** (Application Gateway subnet): The **Subnets** grid will show a subnet named *default*. Change the name of this subnet to *myAGSubnet*.<br>The application gateway subnet can contain only application gateways. No other resources are allowed. ++ - **Subnet name** (backend server subnet): In the second row of the **Subnets** grid, enter *myBackendSubnet* in the **Subnet name** column. ++ - **Address range** (backend server subnet): In the second row of the **Subnets** Grid, enter an address range that doesn't overlap with the address range of *myAGSubnet*. For example, if the address range of *myAGSubnet* is 10.0.0.0/24, enter *10.0.1.0/24* for the address range of *myBackendSubnet*. ++ Select **OK** to close the **Create virtual network** window and save the virtual network settings. ++  + +3. On the **Basics** tab, accept the default values for the other settings and then select **Next: Frontends**. ++### Frontends tab ++1. On the **Frontends** tab, verify **Frontend IP address type** is set to **Public**. <br>You can configure the Frontend IP to be Public or Private as per your use case. In this example, you'll choose a Public Frontend IP. + > [!NOTE] + > For the Application Gateway v2 SKU, there must be a **Public** frontend IP configuration. You can still have both a Public and a Private frontend IP configuration, but Private only frontend IP configuration (Only ILB mode) is currently not enabled for the v2 SKU. ++2. Select **Add new** for the **Public IP address** and enter *myAGPublicIPAddress* for the public IP address name, and then select **OK**. ++  ++3. Select **Next: Backends**. ++### Backends tab ++The backend pool is used to route requests to the backend servers that serve the request. Backend pools can be composed of NICs, Virtual Machine Scale Sets, public IP addresses, internal IP addresses, fully qualified domain names (FQDN), and multi-tenant backends like Azure App Service. In this example, you'll create an empty backend pool with your application gateway and then add backend targets to the backend pool. ++1. On the **Backends** tab, select **Add a backend pool**. ++2. In the **Add a backend pool** window that opens, enter the following values to create an empty backend pool: ++ - **Name**: Enter *myBackendPool* for the name of the backend pool. + - **Add backend pool without targets**: Select **Yes** to create a backend pool with no targets. You'll add backend targets after creating the application gateway. ++3. In the **Add a backend pool** window, select **Add** to save the backend pool configuration and return to the **Backends** tab. ++  ++4. On the **Backends** tab, select **Next: Configuration**. ++### Configuration tab ++On the **Configuration** tab, you'll connect the frontend and backend pool you created using a routing rule. ++1. Select **Add a routing rule** in the **Routing rules** column. ++2. In the **Add a routing rule** window that opens, enter the following values for Rule name and Priority: ++ - **Rule name**: Enter *myRoutingRule* for the name of the rule. + - **Priority**: The priority value should be between 1 and 20000 (where 1 represents highest priority and 20000 represents lowest) - for the purposes of this quickstart, enter *100* for the priority. ++3. A routing rule requires a listener. On the **Listener** tab within the **Add a routing rule** window, enter the following values for the listener: ++ - **Listener name**: Enter *myListener* for the name of the listener. + - **Frontend IP**: Select **Public** to choose the public IP you created for the frontend. + + Accept the default values for the other settings on the **Listener** tab, then select the **Backend targets** tab to configure the rest of the routing rule. ++  ++4. On the **Backend targets** tab, select **myBackendPool** for the **Backend target**. ++5. For the **Backend setting**, select **Add new** to add a new Backend setting. The Backend setting will determine the behavior of the routing rule. In the **Add Backend setting** window that opens, enter *myBackendSetting* for the **Backend settings name** and *80* for the **Backend port**. Accept the default values for the other settings in the **Add Backend setting** window, then select **Add** to return to the **Add a routing rule** window. ++  ++6. On the **Add a routing rule** window, select **Add** to save the routing rule and return to the **Configuration** tab. ++  ++7. Select **Next: Tags** and then **Next: Review + create**. ++### Review + create tab ++Review the settings on the **Review + create** tab, and then select **Create** to create the virtual network, the public IP address, and the application gateway. It may take several minutes for Azure to create the application gateway. Wait until the deployment finishes successfully before moving on to the next section. ++## Enable DDoS protection ++Azure DDoS protection Standard is enabled at the virtual network where the resource you want to protect reside. ++1. In the search box at the top of the portal, enter **Virtual network**. Select **Virtual networks** in the search results. ++2. Select **myVNet**. ++3. Select **DDoS protection** in **Settings**. ++4. Select **Enable**. ++5. In the pull-down box in DDoS protection plan, select **myDDoSProtectionPlan**. ++ :::image type="content" source="./media/tutorial-protect-application-gateway/enable-ddos-vnet.png" alt-text="Screenshot of ddos protection."::: ++6. Select **Save**. ++## Add backend targets ++In this example, you'll use virtual machines as the target backend. You can either use existing virtual machines or create new ones. You'll create two virtual machines as backend servers for the application gateway. ++To do this, you'll: ++1. Create two new VMs, *myVM* and *myVM2*, to be used as backend servers. +2. Install IIS on the virtual machines to verify that the application gateway was created successfully. +3. Add the backend servers to the backend pool. ++### Create a virtual machine ++1. On the Azure portal menu or from the **Home** page, select **Create a resource**. The **New** window appears. +2. Select **Windows Server 2016 Datacenter** in the **Popular** list. The **Create a virtual machine** page appears.<br>Application Gateway can route traffic to any type of virtual machine used in its backend pool. In this example, you use a Windows Server 2016 Datacenter virtual machine. +3. Enter these values in the **Basics** tab for the following virtual machine settings: ++ - **Resource group**: Select **myResourceGroupAG** for the resource group name. + - **Virtual machine name**: Enter *myVM* for the name of the virtual machine. + - **Region**: Select the same region where you created the application gateway. + - **Username**: Type a name for the administrator user name. + - **Password**: Type a password. + - **Public inbound ports**: None. +4. Accept the other defaults and then select **Next: Disks**. +5. Accept the **Disks** tab defaults and then select **Next: Networking**. +6. On the **Networking** tab, verify that **myVNet** is selected for the **Virtual network** and the **Subnet** is set to **myBackendSubnet**. Accept the other defaults and then select **Next: Management**.<br>Application Gateway can communicate with instances outside of the virtual network that it is in, but you need to ensure there's IP connectivity. +7. On the **Management** tab, set **Boot diagnostics** to **Disable**. Accept the other defaults and then select **Review + create**. +8. On the **Review + create** tab, review the settings, correct any validation errors, and then select **Create**. +9. Wait for the virtual machine creation to complete before continuing. ++### Install IIS for testing ++In this example, you install IIS on the virtual machines to verify Azure created the application gateway successfully. ++1. Open Azure PowerShell. ++ Select **Cloud Shell** from the top navigation bar of the Azure portal and then select **PowerShell** from the drop-down list. ++  ++2. Run the following command to install IIS on the virtual machine. Change the *Location* parameter if necessary: ++ ```azurepowershell + Set-AzVMExtension ` + -ResourceGroupName myResourceGroupAG ` + -ExtensionName IIS ` + -VMName myVM ` + -Publisher Microsoft.Compute ` + -ExtensionType CustomScriptExtension ` + -TypeHandlerVersion 1.4 ` + -SettingString '{"commandToExecute":"powershell Add-WindowsFeature Web-Server; powershell Add-Content -Path \"C:\\inetpub\\wwwroot\\Default.htm\" -Value $($env:computername)"}' ` + -Location EastUS + ``` ++3. Create a second virtual machine and install IIS by using the steps that you previously completed. Use *myVM2* for the virtual machine name and for the **VMName** setting of the **Set-AzVMExtension** cmdlet. ++### Add backend servers to backend pool ++1. On the Azure portal menu, select **All resources** or search for and select *All resources*. Then select **myAppGateway**. ++2. Select **Backend pools** from the left menu. ++3. Select **myBackendPool**. ++4. Under **Backend targets**, **Target type**, select **Virtual machine** from the drop-down list. ++5. Under **Target**, select the **myVM** and **myVM2** virtual machines and their associated network interfaces from the drop-down lists. ++ > [!div class="mx-imgBorder"] + >  ++6. Select **Save**. ++7. Wait for the deployment to complete before proceeding to the next step. ++## Test the application gateway ++Although IIS isn't required to create the application gateway, you installed it in this quickstart to verify if Azure successfully created the application gateway. ++Use IIS to test the application gateway: ++1. Find the public IP address for the application gateway on its **Overview** page. Or, you can select **All resources**, enter *myAGPublicIPAddress* in the search box, and then select it in the search results. Azure displays the public IP address on the **Overview** page. +2. Copy the public IP address, and then paste it into the address bar of your browser to browse that IP address. +3. Check the response. A valid response verifies that the application gateway was successfully created and can successfully connect with the backend. ++  ++ Refresh the browser multiple times and you should see connections to both myVM and myVM2. ++## Clean up resources ++When you no longer need the resources that you created with the application gateway, delete the resource group. When you delete the resource group, you also remove the application gateway and all the related resources. ++To delete the resource group: ++1. On the Azure portal menu, select **Resource groups** or search for and select *Resource groups*. +2. On the **Resource groups** page, search for **myResourceGroupAG** in the list, then select it. +3. On the **Resource group page**, select **Delete resource group**. +4. Enter *myResourceGroupAG* under **TYPE THE RESOURCE GROUP NAME** and then select **Delete** ++## Next steps ++Advance to the next article to learn how to: ++> [!div class="nextstepaction"] +> [Configure an application gateway with TLS termination using the Azure portal](create-ssl-portal.md) |
applied-ai-services | Concept Custom Label Tips | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/applied-ai-services/form-recognizer/concept-custom-label-tips.md | recommendations: false This article highlights the best methods for labeling custom model datasets in the Form Recognizer Studio. Labeling documents can be time consuming when you have a large number of labels, long documents, or documents with varying structure. These tips should help you label documents more efficiently. +## Video: Custom labels best practices ++* The following video is the second of two presentations intended to help you build custom models with higher accuracy (the first presentation explores [How to create a balanced data set](concept-custom-label.md#video-custom-label-tips-and-pointers)). ++* Here, we'll examine best practices for labeling your selected documents. With semantically relevant and consistent labeling, you should see an improvement in model performance.</br></br> ++ > [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RE5fZKB ] + ## Search The Studio now includes a search box for instances when you know you need to find specific words to label, but just don't know where they're located in the document. Simply search for the word or phrase and navigate to the specific section in the document to label the occurrence. |
applied-ai-services | Concept Custom Label | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/applied-ai-services/form-recognizer/concept-custom-label.md | A labeled dataset consists of several files: * A `{file}.labels.json` file is created or updated when a field is labeled in a document. The label file contains the spans of text and associated polygons from the layout output for each span of text the user adds as a value for a specific field. +## Video: Custom label tips and pointers ++* The following video is the first of two presentations intended to help you build custom models with higher accuracy (The second presentation examines [Best practices for labeling documents](concept-custom-label-tips.md#video-custom-labels-best-practices)). ++* Here, we'll explore how to create a balanced data set and select the right documents to label. This process will set you on the path to higher quality models.</br></br> ++ > [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RWWHru] + ## Create a balanced dataset Before you start labeling, it's a good idea to look at a few different samples of the document to identify which samples you want to use in your labeled dataset. A balanced dataset represents all the typical variations you would expect to see for the document. Creating a balanced dataset will result in a model with the highest possible accuracy. A few examples to consider are: * **Document formats**: If you expect to analyze both digital and scanned documents, add a few examples of each type to the training dataset -* **Variations (template model)**: Consider splitting the dataset into folders and train a model for each of variation. Variations that include either structure or layout should be split into different models. You can then compose the individual models into a single [composed model](concept-composed-models.md). +* **Variations (template model)**: Consider splitting the dataset into folders and train a model for each of variation. Any variations that include either structure or layout should be split into different models. You can then compose the individual models into a single [composed model](concept-composed-models.md). * **Variations (Neural models)**: When your dataset has a manageable set of variations, about 15 or fewer, create a single dataset with a few samples of each of the different variations to train a single model. If the number of template variations is larger than 15, you'll train multiple models and [compose](concept-composed-models.md) them together. |
applied-ai-services | Build A Custom Model | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/applied-ai-services/form-recognizer/how-to-guides/build-a-custom-model.md | Follow these tips to further optimize your data set for training: Once you've put together the set of forms or documents for training, you'll need to upload it to an Azure blob storage container. If you don't know how to create an Azure storage account with a container, following the [Azure Storage quickstart for Azure portal](../../../storage/blobs/storage-quickstart-blobs-portal.md). You can use the free pricing tier (F0) to try the service, and upgrade later to a paid tier for production. +## Video: Train your custom model ++* Once you've gathered and uploaded your training dataset, you're ready to train your custom model. In the following video, we'll create a project and explore some of the fundamentals for successfully labeling and training a model.</br></br> ++ > [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RE5fX1c] + ## Create a project in the Form Recognizer Studio The Form Recognizer Studio provides and orchestrates all the API calls required to complete your dataset and train your model. |
applied-ai-services | Overview | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/applied-ai-services/form-recognizer/overview.md | Azure Form Recognizer is a cloud-based [Azure Applied AI Service](../../applied- | **Prebuilt models** | ● [**W-2 form model**](concept-w2.md) </br>● [**Invoice model**](concept-invoice.md)</br>● [**Receipt model**](concept-receipt.md) </br>● [**Identity (ID) document model**](concept-id-document.md) </br>● [**Business card model**](concept-business-card.md) </br> | **Custom models** | ● [**Custom model**](concept-custom.md) </br>● [**Composed model**](concept-model-overview.md)| +## Video: Form Recognizer models ++The following video introduces Form Recognizer models and their associated output to help you choose the best model to address your document scenario needs.</br></br> ++ > [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/RE5fX1b] + ## Which Form Recognizer model should I use? This section will help you decide which **Form Recognizer v3.0** supported model you should use for your application: |
azure-app-configuration | Howto Recover Deleted Stores In Azure App Configuration | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-app-configuration/howto-recover-deleted-stores-in-azure-app-configuration.md | description: Recover/Purge Azure App Configuration soft deleted Stores -+ Previously updated : 03/01/2022 Last updated : 01/25/2023 # Recover Azure App Configuration stores To create a new App Configuration store in the Azure portal, follow these steps When recovering stores that use customer-managed keys, there are extra steps that need to be performed to access the recovered data. This is because the recovered store, will no longer have a managed identity assigned that has access to the customer-managed key. A new managed identity should be assigned to the store and the customer managed key settings should be reconfigured to use the newly assigned identity. When updating the managed key settings to use the newly assigned identity, ensure to continue using the same key from the key vault. For more details on how to use customer-managed keys in App Configuration stores, refer to [Use customer-managed keys to encrypt your App Configuration data](./concept-customer-managed-keys.md). +> [!NOTE] +> The previous section showed you how to recover a deleted store with CMK enabled. If your deleted store had Event Grid subscriptions, private endpoints or Azure RBAC role assignments, you'll need to recreate these services after recovery. + ## Next steps > [!div class="nextstepaction"] > [Soft-Delete in Azure App Configuration](./concept-soft-delete.md) |
azure-arc | Troubleshoot Resource Bridge | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-arc/resource-bridge/troubleshoot-resource-bridge.md | For example, if you specified the wrong location, or subscription during deploym To resolve this issue, delete the appliance and update the appliance YAML file. Then redeploy and create the resource bridge. -### Failure due to previous deployments +### Connection closed before server preface received -If Arc resource bridge is deployed multiple times, an old token or expired credentials left on the management machine may cause future deployments to fail. +When there are multiple attempts to deploy Arc resource bridge, expired credentials left on the management machine may cause future deployments to fail. The error will contain the message `Unavailable desc = connection closed before server preface received`. This error will surface in various `az arcappliance` commands including `validate`, `prepare` and `delete`. -To prevent this from happening, be sure to run the `az arcappliance delete` command after any failed deployment, or to delete the current bridge before attempting another deployment. The delete command must be run with the latest `arcappliance` Azure CLI extension. To ensure that you have the latest version installed on your machine, run the following command: --```azurecli -az extension update --name arcappliance -``` --If all components of Arc resource bridge are not completely deleted, the residual token or expired credentials may cause future deployments to fail. When this is the case, the error will contain the message `Unavailable desc = connection closed before server preface received` to surface when various `az arcappliance` commands are run, including `prepare` and `delete`. --To resolve this error, the .wssd\python and .wssd\kva folders in the user profile directory need to be deleted from the management machine. You can delete these manually by navigating to the user profile directory (typically `C:\Users\<username>`), then deleting the `.wssd\python` and/or `.wssd\kva` folders. After they are deleted, retry the command that failed. +To resolve this error, the .wssd\python and .wssd\kva folders in the user profile directory need to be manually deleted from the management machine. Depending on where the deployment errored, there may not be a kva folder to delete. You can delete these folders manually by navigating to the user profile directory (typically `C:\Users\<username>`), then deleting the `.wssd\python` and `.wssd\kva` folders. After they are deleted, retry the command that failed. ### Token refresh error If you don't see your problem here or you can't resolve your issue, try one of t - Connect with [@AzureSupport](https://twitter.com/azuresupport), the official Microsoft Azure account for improving customer experience. Azure Support connects the Azure community to answers, support, and experts. -- [Open an Azure support request](../../azure-portal/supportability/how-to-create-azure-support-request.md).+- [Open an Azure support request](../../azure-portal/supportability/how-to-create-azure-support-request.md). |
azure-arc | Overview | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-arc/servers/overview.md | Title: Azure Arc-enabled servers Overview description: Learn how to use Azure Arc-enabled servers to manage servers hosted outside of Azure like an Azure resource. Previously updated : 06/09/2022 Last updated : 02/01/2023 # What is Azure Arc-enabled servers? -Azure Arc-enabled servers lets you manage Windows and Linux physical servers and virtual machines hosted *outside* of Azure, on your corporate network, or other cloud provider. This management experience is designed to be consistent with how you manage native Azure virtual machines, using standard Azure constructs such as Azure Policy and applying tags. +Azure Arc-enabled servers lets you manage Windows and Linux physical servers and virtual machines hosted *outside* of Azure, on your corporate network, or other cloud provider. For the purposes of Azure Arc, these machines hosted outside of Azure are considered hybrid machines. The management of hybrid machines in Azure Arc is designed to be consistent with how you manage native Azure virtual machines, using standard Azure constructs such as Azure Policy and applying tags. (For additional information about hybrid environments, see [What is a hybrid cloud?](https://azure.microsoft.com/resources/cloud-computing-dictionary/what-is-hybrid-cloud-computing)) When a hybrid machine is connected to Azure, it becomes a connected machine and is treated as a resource in Azure. Each connected machine has a Resource ID enabling the machine to be included in a resource group. |
azure-functions | Dotnet Isolated In Process Differences | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/dotnet-isolated-in-process-differences.md | Use the following table to compare feature and functional differences between th | [Supported .NET versions](dotnet-isolated-process-guide.md#supported-versions) | Long Term Support (LTS) versions | [All supported versions](dotnet-isolated-process-guide.md#supported-versions) + .NET Framework | | Core packages | [Microsoft.NET.Sdk.Functions](https://www.nuget.org/packages/Microsoft.NET.Sdk.Functions/) | [Microsoft.Azure.Functions.Worker](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker/)<br/>[Microsoft.Azure.Functions.Worker.Sdk](https://www.nuget.org/packages/Microsoft.Azure.Functions.Worker.Sdk) | | Binding extension packages | [Microsoft.Azure.WebJobs.Extensions.*](https://www.nuget.org/packages?q=Microsoft.Azure.WebJobs.Extensions) | [Microsoft.Azure.Functions.Worker.Extensions.*](https://www.nuget.org/packages?q=Microsoft.Azure.Functions.Worker.Extensions) | -| Durable Functions | [Supported](durable/durable-functions-overview.md) | [Supported (public preview)](https://github.com/microsoft/durabletask-dotnet#usage-with-azure-functions) | +| Durable Functions | [Supported](durable/durable-functions-overview.md) | [Supported](durable/durable-functions-dotnet-isolated-overview.md) | | Model types exposed by bindings | Simple types<br/>[JSON serializable](/dotnet/api/system.text.json.jsonserializeroptions) types<br/>Arrays/enumerations<br/>Service SDK types such as [BlobClient](/dotnet/api/azure.storage.blobs.blobclient)<br/>`IAsyncCollector` (for output bindings) | Simple types<br/>JSON serializable types<br/>Arrays/enumerations | | HTTP trigger model types| [HttpRequest](/dotnet/api/system.net.http.httpclient) / [ObjectResult](/dotnet/api/microsoft.aspnetcore.mvc.objectresult) | [HttpRequestData](/dotnet/api/microsoft.azure.functions.worker.http.httprequestdata?view=azure-dotnet&preserve-view=true) / [HttpResponseData](/dotnet/api/microsoft.azure.functions.worker.http.httpresponsedata?view=azure-dotnet&preserve-view=true) | | Output binding interaction | Return values (single output only)<br/>`out` parameters<br/>`IAsyncCollector` | Return values (expanded model with single or [multiple outputs](dotnet-isolated-process-guide.md#multiple-output-bindings)) | To learn more, see: + [Develop .NET isolated worker process functions](dotnet-isolated-process-guide.md) [ILogger]: /dotnet/api/microsoft.extensions.logging.ilogger-[ILogger<T>]: /dotnet/api/microsoft.extensions.logging.logger-1 +[ILogger<T>]: /dotnet/api/microsoft.extensions.logging.logger-1 |
azure-functions | Durable Functions Bindings | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-bindings.md | The orchestration trigger binding supports both inputs and outputs. Here are som The following example code shows what the simplest "Hello World" orchestrator function might look like. Note that this example orchestrator doesn't actually schedule any tasks. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("HelloWorld")] public static string Run([OrchestrationTrigger] IDurableOrchestrationContext con > [!NOTE] > The previous code is for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions Versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("HelloWorld")] +public static string Run([OrchestrationTrigger] TaskOrchestrationContext context, string name) +{ + return $"Hello {name}!"; +} +``` ++> [!NOTE] +> In both Durable functions in-proc and in .NET-isolated, the orchestration input can be extracted via `context.GetInput<T>()`. However, .NET-isolated also supports the input being supplied as a parameter, as shown above. The input binding will bind to the first parameter which has no binding attribute on it and is not a well-known type already covered by other input bindings (ie: `FunctionContext`). + # [JavaScript](#tab/javascript) ```javascript public String helloWorldOrchestration( Most orchestrator functions call activity functions, so here is a "Hello World" example that demonstrates how to call an activity function: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("HelloWorld")] public static async Task<string> Run( > [!NOTE] > The previous code is for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("HelloWorld")] +public static async Task<string> Run( + [OrchestrationTrigger] TaskOrchestrationContext context, string name) +{ + string result = await context.CallActivityAsync<string>("SayHello", name); + return result; +} +``` + # [JavaScript](#tab/javascript) ```javascript The activity trigger binding supports both inputs and outputs, just like the orc The following example code shows what a simple `SayHello` activity function might look like: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("SayHello")] public static string SayHello([ActivityTrigger] string name) } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++In the .NET-isolated worker, only serializable types representing your input are supported for the `[ActivityTrigger]`. ++```csharp +[FunctionName("SayHello")] +public static string SayHello([ActivityTrigger] string name) +{ + return $"Hello {name}!"; +} +``` + # [JavaScript](#tab/javascript) ```javascript In .NET functions, you typically bind to [IDurableClient](/dotnet/api/microsoft. Here's an example queue-triggered function that starts a "HelloWorld" orchestration. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("QueueStart")] public static Task Run( > [!NOTE] > The previous C# code is for Durable Functions 2.x. For Durable Functions 1.x, you must use `OrchestrationClient` attribute instead of the `DurableClient` attribute, and you must use the `DurableOrchestrationClient` parameter type instead of `IDurableOrchestrationClient`. For more information about the differences between versions, see the [Durable Functions Versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("QueueStart")] +public static Task Run( + [QueueTrigger("durable-function-trigger")] string input, + [DurableClient] DurableTaskClient client) +{ + // Orchestration input comes from the queue message content. + return client.ScheduleNewOrchestrationInstanceAsync("HelloWorld", input); +} +``` + # [JavaScript](#tab/javascript) **function.json** If you're using JavaScript, Python, or PowerShell, the entity trigger is defined ``` > [!NOTE]-> Entity triggers are not yet supported in Java. +> Entity triggers are not yet supported in Java or in the .NET-isolated worker. By default, the name of an entity is the name of the function. |
azure-functions | Durable Functions Diagnostics | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-diagnostics.md | For more information about what log events are available, see the [Durable Task It's important to keep the orchestrator replay behavior in mind when writing logs directly from an orchestrator function. For example, consider the following orchestrator function: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("FunctionChain")] public static async Task Run( } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("FunctionChain")] +public static async Task Run( + [OrchestrationTrigger] TaskOrchestrationContext context, + FunctionContext executionContext) +{ + ILogger log = executionContext.GetLogger("FunctionChain"); + log.LogInformation("Calling F1."); + await context.CallActivityAsync("F1"); + log.LogInformation("Calling F2."); + await context.CallActivityAsync("F2"); + log.LogInformation("Calling F3"); + await context.CallActivityAsync("F3"); + log.LogInformation("Done!"); +} +``` + # [JavaScript](#tab/javascript) ```javascript Done! If you want to only write logs on non-replay executions, you can write a conditional expression to log only if the "is replaying" flag is `false`. Consider the example above, but this time with replay checks. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("FunctionChain")] public static async Task Run( > [!NOTE] > The previous C# examples are for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++In Durable Functions for .NET-isolated, you can create an `ILogger` that automatically filters out log statements during replay. The main difference with Durable Functions in-proc is that you do not provide an existing `ILogger`. This logger is created via the `TaskOrchestrationContext.CreateReplaySafeLogger` overloads. ++```csharp +[Function("FunctionChain")] +public static async Task Run([OrchestrationTrigger] TaskOrchestrationContext context) +{ + ILogger log = context.CreateReplaySafeLogger("FunctionChain"); + log.LogInformation("Calling F1."); + await context.CallActivityAsync("F1"); + log.LogInformation("Calling F2."); + await context.CallActivityAsync("F2"); + log.LogInformation("Calling F3"); + await context.CallActivityAsync("F3"); + log.LogInformation("Done!"); +} +``` ++> [!NOTE] +> The ability to wrap an existing `ILogger` into a replay-safe logger has been removed in Durable Functions for .NET isolated worker. + # [JavaScript](#tab/javascript) ```javascript Done! Custom orchestration status lets you set a custom status value for your orchestrator function. This custom status is then visible to external clients via the [HTTP status query API](durable-functions-http-api.md#get-instance-status) or via language-specific API calls. The custom orchestration status enables richer monitoring for orchestrator functions. For example, the orchestrator function code can invoke the "set custom status" API to update the progress for a long-running operation. A client, such as a web page or other external system, could then periodically query the HTTP status query APIs for richer progress information. Sample code for setting a custom status value in an orchestrator function is provided below: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("SetStatusTest")] public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrat > [!NOTE] > The previous C# example is for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("SetStatusTest")] +public static async Task SetStatusTest([OrchestrationTrigger] TaskOrchestrationContext context) +{ + // ...do work... ++ // update the status of the orchestration with some arbitrary data + var customStatus = new { completionPercentage = 90.0, status = "Updating database records" }; + context.SetCustomStatus(customStatus); ++ // ...do more work... +} +``` + # [JavaScript](#tab/javascript) ```javascript |
azure-functions | Durable Functions Dotnet Entities | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-dotnet-entities.md | We currently offer two APIs for defining entities: This article focuses primarily on the class-based syntax, as we expect it to be better suited for most applications. However, the [function-based syntax](#function-based-syntax) may be appropriate for applications that wish to define or manage their own abstractions for entity state and operations. Also, it may be appropriate for implementing libraries that require genericity not currently supported by the class-based syntax. > [!NOTE]-> The class-based syntax is just a layer on top of the function-based syntax, so both variants can be used interchangeably in the same application. +> The class-based syntax is just a layer on top of the function-based syntax, so both variants can be used interchangeably in the same application. ++> [!NOTE] +> Entities are not currently supported in Durable Functions for the dotnet-isolated worker. ## Defining entity classes |
azure-functions | Durable Functions Dotnet Isolated Overview | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-dotnet-isolated-overview.md | + + Title: Overview of Durable Functions in the .NET isolated worker - Azure +description: Learn about Durable Functions in the Azure Functions .NET isolated worker process, which supports non-LTS versions of .NET and .NET Framework apps. ++ Last updated : 01/24/2023++ms.devlang: csharp +#Customer intent: As a developer, I want to learn about Durable Functions for the Azure Functions .NET isolated worker process. +++# Overview of Durable Functions in the .NET isolated worker ++This article is an overview of Durable Functions in the [.NET isolated worker](../dotnet-isolated-process-guide.md). The isolated worker allows your Durable Functions app to run on a .NET version different than that of the Azure Functions host. ++## Why use Durable Functions in the .NET isolated worker? ++Using this model lets you get all the great benefits that come with the Azure Functions .NET isolated worker process. For more information, see [here](../dotnet-isolated-process-guide.md#why-net-functions-isolated-worker-process). Additionally, this new SDK includes some new [features](#feature-improvements-over-in-process-durable-functions). ++### Feature improvements over in-process Durable Functions ++- Orchestration input can be injected directly: `MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, T input)` +- Support for strongly typed calls and class-based activities and orchestrations (NOTE: in preview. For more information, see [here](#source-generator-and-class-based-activities-and-orchestrations).) +- Plus all the benefits of the Azure Functions .NET isolated worker. ++### Feature parity with in-process Durable Functions ++Not all features from in-process Durable Functions have been migrated to the isolated worker yet. Some known missing features that will be addressed at a later date are: ++- Durable Entities +- `CallHttpAsync` ++### Source generator and class-based activities and orchestrations ++**Requirement**: add `<PackageReference Include="Microsoft.DurableTask.Generators" Version="1.0.0-preview.1" />` to your project. ++By adding the source generator package, you get access to two new features: ++- **Class-based activities and orchestrations**, an alternative way to write Durable Functions. Instead of "function-based", you write strongly-typed classes, which inherit types from the Durable SDK. +- **Strongly typed extension methods** for invoking sub orchestrations and activities. These extension methods can also be used from "function-based" activities and orchestrations. ++#### Function-based example ++```csharp +public static class MyFunctions +{ + [Function(nameof(MyActivity))] + public static async Task<string> MyActivity([ActivityTrigger] string input) + { + // implementation + } ++ [Function(nameof(MyOrchestration))] + public static async Task<string> MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, string input) + { + // implementation + return await context.CallActivityAsync(nameof(MyActivity), input); + } +} +``` ++#### Class-based example ++```csharp +[DurableTask(nameof(MyActivity))] +public class MyActivity : TaskActivity<string, string> +{ + private readonly ILogger logger; ++ public MyActivity(ILogger<SayHelloTyped> logger) // activites have access to DI. + { + this.logger = logger; + } ++ public async override Task<string> RunAsync(TaskActivityContext context, string input) + { + // implementation + } +} ++[DurableTask(nameof(MyOrchestration))] +public class MyOrchestration : TaskOrchestrator<string, string> +{ + public async override Task<string> RunAsync(TaskOrchestrationContext context, string input) + { + ILogger logger = context.CreateReplaySafeLogger<MyOrchestration>(); // orchestrations do NOT have access to DI. ++ // An extension method was generated for directly invoking "MyActivity". + return await context.CallMyActivityAsync(input); + } +} +``` ++## Migration guide ++This guide assumes you're starting with a .NET Durable Functions 2.x project. ++### Update your project ++The first step is to update your project to [Azure Functions .NET isolated](../migrate-version-3-version-4.md). Then, update your Durable Functions NuGet package references. ++Old: ++```xml +<ItemGroup> + <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="2.9.0" /> +</ItemGroup> +``` ++New: ++```xml +<ItemGroup> + <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.0.0" /> +</ItemGroup> +``` ++### Update your code ++Durable Functions for .NET isolated worker is an entirely new package with different types and namespaces. There are required changes to your code as a result, but many of the APIs line up with no changes needed. ++#### Host.json schema ++The schema for Durable Functions .NET isolated worker and Durable Functions 2.x has remained the same, no changes should be needed. ++#### Public interface changes ++This table isn't an exhaustive list of changes. ++| 2.x | Isolated | +| - | - | +| `IDurableOrchestrationClient` | `DurableTaskClient` | +| `IDurableOrchestrationClient.StartNewAsync` | `DurableTaskClient.ScheduleNewOrchestrationInstanceAsync` | +| `IDurableOrchestrationContext` | `TaskOrchestrationContext` | +| `IDurableOrchestrationContext.GetInput<T>()` | `TaskOrchestrationContext.GetInput<T>()` or inject input as a parameter: `MyOrchestration([OrchestrationTrigger] TaskOrchestrationContext context, T input)` | +| `DurableActivityContext` | No equivalent | +| `DurableActivityContext.GetInput<T>()` | Inject input as a parameter `MyActivity([ActivityTrigger] T input)` | +| `CallActivityWithRetryAsync` | `CallActivityAsync`, include `TaskOptions` parameter with retry details. | +| `CallSubOrchestratorWithRetryAsync` | `CallSubOrchestratorAsync`, include `TaskOptions` parameter with retry details. | +| `CallHttpAsync` | No equivalent. Instead, write an activity that invokes your desired HTTP API. | +| `CreateReplaySafeLogger(ILogger)` | `CreateReplaySafeLogger<T>()` or `CreateReplaySafeLogger(string)` | ++#### Behavioral changes ++- Serialization default behavior has changed from `Newtonsoft.Json` to `System.Text.Json`. For more information, see [here](./durable-functions-serialization-and-persistence.md). |
azure-functions | Durable Functions Entities | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-entities.md | Entity functions define operations for reading and updating small pieces of stat Entities provide a means for scaling out applications by distributing the work across many entities, each with a modestly sized state. > [!NOTE]-> Entity functions and related functionality are only available in [Durable Functions 2.0](durable-functions-versions.md#migrate-from-1x-to-2x) and above. They are currently supported in .NET, JavaScript, and Python, but not in PowerShell or Java. +> Entity functions and related functionality are only available in [Durable Functions 2.0](durable-functions-versions.md#migrate-from-1x-to-2x) and above. They are currently supported in .NET in-proc, JavaScript, and Python, but not in .NET isolated worker, PowerShell, or Java. ## General concepts |
azure-functions | Durable Functions Error Handling | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-error-handling.md | Any exception that is thrown in an activity function is marshaled back to the or For example, consider the following orchestrator function that transfers funds from one account to another: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("TransferFunds")] public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext > [!NOTE] > The previous C# examples are for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[FunctionName("TransferFunds")] +public static async Task Run( + [OrchestrationTrigger] TaskOrchestrationContext context, TransferOperation transferDetails) +{ + await context.CallActivityAsync("DebitAccount", + new + { + Account = transferDetails.SourceAccount, + Amount = transferDetails.Amount + }); ++ try + { + await context.CallActivityAsync("CreditAccount", + new + { + Account = transferDetails.DestinationAccount, + Amount = transferDetails.Amount + }); + } + catch (Exception) + { + // Refund the source account. + // Another try/catch could be used here based on the needs of the application. + await context.CallActivityAsync("CreditAccount", + new + { + Account = transferDetails.SourceAccount, + Amount = transferDetails.Amount + }); + } +} +``` + # [JavaScript](#tab/javascript) ```javascript If the first **CreditAccount** function call fails, the orchestrator function co When you call activity functions or sub-orchestration functions, you can specify an automatic retry policy. The following example attempts to call a function up to three times and waits 5 seconds between each retry: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("TimerOrchestratorWithRetry")] public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext > [!NOTE] > The previous C# examples are for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[FunctionName("TimerOrchestratorWithRetry")] +public static async Task Run([OrchestrationTrigger] TaskOrchestrationContext context) +{ + var options = TaskOptions.FromRetryPolicy(new RetryPolicy( + maxNumberOfAttempts: 3, + firstRetryInterval: TimeSpan.FromSeconds(5))); ++ await context.CallActivityAsync("FlakyFunction", options: options); ++ // ... +} +``` + # [JavaScript](#tab/javascript) ```javascript The activity function call in the previous example takes a parameter for configu ## Custom retry handlers -When using the .NET isolated worker or Java, you also have the option to implement retry handlers in code. This is useful when declarative retry policies are not expressive enough. For languages that don't support custom retry handlers, you still have the option of implementing retry policies using loops, exception handling, and timers for injecting delays between retries. +When using the .NET or Java, you also have the option to implement retry handlers in code. This is useful when declarative retry policies are not expressive enough. For languages that don't support custom retry handlers, you still have the option of implementing retry policies using loops, exception handling, and timers for injecting delays between retries. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ++```csharp +RetryOptions retryOptions = new RetryOptions( + firstRetryInterval: TimeSpan.FromSeconds(5), + maxNumberOfAttempts: int.MaxValue) + { + Handle = exception => + { + // True to handle and try again, false to not handle and throw. + if (exception is TaskFailedException failure) + { + // Exceptions from TaskActivities are always this type. Inspect the + // inner Exception to get more details. + } ++ return false; + }; + } ++await ctx.CallActivityWithRetryAsync("FlakeyActivity", retryOptions, null); +``` ++# [C# (Isolated)](#tab/csharp-isolated) ```csharp TaskOptions retryOptions = TaskOptions.FromRetryHandler(retryContext => try { You might want to abandon a function call within an orchestrator function if it's taking too long to complete. The proper way to do this today is by creating a [durable timer](durable-functions-timers.md) with an "any" task selector, as in the following example: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("TimerOrchestrator")] public static async Task<bool> Run([OrchestrationTrigger] IDurableOrchestrationC > [!NOTE] > The previous C# examples are for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("TimerOrchestrator")] +public static async Task<bool> Run([OrchestrationTrigger] TaskOrchestrationContext context) +{ + TimeSpan timeout = TimeSpan.FromSeconds(30); + DateTime deadline = context.CurrentUtcDateTime.Add(timeout); ++ using (var cts = new CancellationTokenSource()) + { + Task activityTask = context.CallActivityAsync("FlakyFunction"); + Task timeoutTask = context.CreateTimer(deadline, cts.Token); ++ Task winner = await Task.WhenAny(activityTask, timeoutTask); + if (winner == activityTask) + { + // success case + cts.Cancel(); + return true; + } + else + { + // timeout case + return false; + } + } +} +``` + # [JavaScript](#tab/javascript) ```javascript |
azure-functions | Durable Functions Isolated Create First Csharp | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-isolated-create-first-csharp.md | static class HelloSequence ## Configure storage -Your app needs a storage for runtime information. To use [Azurite](https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio-code), which is an emulator for Azure Storage, set `AzureWebJobStorage` in _local.settings.json_ to `UseDevelopmentStorage=true`: +Your app needs a storage for runtime information. To use [Azurite](../../storage/common/storage-use-azurite.md?tabs=visual-studio-code), which is an emulator for Azure Storage, set `AzureWebJobStorage` in _local.settings.json_ to `UseDevelopmentStorage=true`: ```json { Your app needs a storage for runtime information. To use [Azurite](https://learn ``` You can install the Azurite extension on Visual Studio Code and start it by running `Azurite: Start` in the command palette. -There are other storage options you can use for your Durable Functions app. See [Durable Functions storage providers](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-storage-providers) to learn more about different storage options and what benefits they provide. +There are other storage options you can use for your Durable Functions app. See [Durable Functions storage providers](durable-functions-storage-providers.md) to learn more about different storage options and what benefits they provide. ## Test the function locally To complete this tutorial: * Install [Visual Studio 2022](https://visualstudio.microsoft.com/vs/). Make sure that the **Azure development** workload is also installed. Visual Studio 2019 also supports Durable Functions development, but the UI and steps differ. -* Verify that you have the [Azurite Emulator](../../storage/common//storage-use-azurite.md) installed and running. +* Verify that you have the [Azurite Emulator](../../storage/common/storage-use-azurite.md) installed and running. [!INCLUDE [quickstarts-free-trial-note](../../../includes/quickstarts-free-trial-note.md)] The Azure Functions template creates a project that can be published to a functi 5. Select **Create** to create an empty function project. This project has the basic configuration files needed to run your functions. Make sure the box for _"Use Azurite for runtime storage account (AzureWebJobStorage)"_ is checked. This will use Azurite emulator. -Note that there are other storage options you can use for your Durable Functions app. See [Durable Functions storage providers](https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-storage-providers) to learn more about different storage options and what benefits they provide. +Note that there are other storage options you can use for your Durable Functions app. See [Durable Functions storage providers](durable-functions-storage-providers.md) to learn more about different storage options and what benefits they provide. ## Add NuGet package references |
azure-functions | Durable Functions Orchestrations | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-orchestrations.md | When an orchestration function is given more work to do (for example, a response The event-sourcing behavior of the Durable Task Framework is closely coupled with the orchestrator function code you write. Suppose you have an activity-chaining orchestrator function, like the following orchestrator function: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("HelloCities")] public static async Task<List<string>> Run( } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("HelloCities")] +public static async Task<List<string>> Run( + [OrchestrationTrigger] TaskOrchestrationContext context) +{ + var outputs = new List<string>(); ++ outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo")); + outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle")); + outputs.Add(await context.CallActivityAsync<string>("SayHello", "London")); ++ // returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"] + return outputs; +} +``` + # [JavaScript](#tab/javascript) ```javascript The `LockAsync` acquires the durable lock(s) and returns an `IDisposable` that e The critical section feature is also useful for coordinating changes to durable entities. For more information about critical sections, see the [Durable entities "Entity coordination"](durable-functions-entities.md#entity-coordination) topic. > [!NOTE]-> Critical sections are available in Durable Functions 2.0 and above. Currently, only .NET orchestrations implement this feature. +> Critical sections are available in Durable Functions 2.0. Currently, only .NET in-proc orchestrations implement this feature. Entities and critical sections are not yet available in Durable Functions for dotnet-isolated worker. ### Calling HTTP endpoints (Durable Functions 2.x) Orchestrator functions aren't permitted to do I/O, as described in [orchestrator function code constraints](durable-functions-code-constraints.md). The typical workaround for this limitation is to wrap any code that needs to do I/O in an activity function. Orchestrations that interact with external systems frequently use activity functions to make HTTP calls and return the result to the orchestration. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) To simplify this common pattern, orchestrator functions can use the `CallHttpAsync` method to invoke HTTP APIs directly. public static async Task CheckSiteAvailable( } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++The feature is not currently supported in dotnet-isolated worker. Instead, write an activity which performs the desired HTTP call. + # [JavaScript](#tab/javascript) ```javascript def orchestrator_function(context: df.DurableOrchestrationContext): if res.status_code >= 400: # handing of error code goes here ```+ # [PowerShell](#tab/powershell) The feature is not currently supported in PowerShell. For more information and for detailed examples, see the [HTTP features](durable- It isn't possible to pass multiple parameters to an activity function directly. The recommendation is to pass in an array of objects or composite objects. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) In .NET you can also use [ValueTuple](/dotnet/csharp/tuples) objects. The following sample is using new features of [ValueTuple](/dotnet/csharp/tuples) added with [C# 7](/dotnet/csharp/whats-new/csharp-7#tuples): public static async Task<object> Mapper([ActivityTrigger] IDurableActivityContex } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++In .NET you can also use [ValueTuple](/dotnet/csharp/tuples) objects. The following sample is using new features of [ValueTuple](/dotnet/csharp/tuples) added with [C# 7](/dotnet/csharp/whats-new/csharp-7#tuples): ++```csharp +[Function("GetCourseRecommendations")] +public static async Task<object> RunOrchestrator( + [OrchestrationTrigger] TaskOrchestrationContext context, int universityYear) +{ + string major = "ComputerScience"; ++ object courseRecommendations = await context.CallActivityAsync<object>( + "CourseRecommendations", + (major, universityYear)); + return courseRecommendations; +} ++[FunctionName("CourseRecommendations")] +public static async Task<object> Mapper( + [ActivityTrigger] (string Major, int UniversityYear) inputs, FunctionContext executionContext) +{ + // retrieve and return course recommendations by major and university year + return new + { + major = studentInfo.Major, + universityYear = studentInfo.UniversityYear, + recommendedCourses = new [] + { + "Introduction to .NET Programming", + "Introduction to Linux", + "Becoming an Entrepreneur" + } + }; +} +``` + # [JavaScript](#tab/javascript) #### Orchestrator |
azure-functions | Durable Functions Overview | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-overview.md | You can use Durable Functions to implement the function chaining pattern concise In this example, the values `F1`, `F2`, `F3`, and `F4` are the names of other functions in the same function app. You can implement control flow by using normal imperative coding constructs. Code executes from the top down. The code can involve existing language control flow semantics, like conditionals and loops. You can include error handling logic in `try`/`catch`/`finally` blocks. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("Chaining")] public static async Task<object> Run( You can use the `context` parameter to invoke other functions by name, pass parameters, and return function output. Each time the code calls `await`, the Durable Functions framework checkpoints the progress of the current function instance. If the process or virtual machine recycles midway through the execution, the function instance resumes from the preceding `await` call. For more information, see the next section, Pattern #2: Fan out/fan in. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("Chaining")] +public static async Task<object> Run( + [OrchestrationTrigger] TaskOrchestrationContext context) +{ + try + { + var x = await context.CallActivityAsync<object>("F1", null); + var y = await context.CallActivityAsync<object>("F2", x); + var z = await context.CallActivityAsync<object>("F3", y); + return await context.CallActivityAsync<object>("F4", z); + } + catch (Exception) + { + // Error handling or compensation goes here. + } +} +``` ++You can use the `context` parameter to invoke other functions by name, pass parameters, and return function output. Each time the code calls `await`, the Durable Functions framework checkpoints the progress of the current function instance. If the process or virtual machine recycles midway through the execution, the function instance resumes from the preceding `await` call. For more information, see the next section, Pattern #2: Fan out/fan in. + # [JavaScript](#tab/javascript) ```javascript With normal functions, you can fan out by having the function send multiple mess The Durable Functions extension handles this pattern with relatively simple code: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("FanOutFanIn")] The fan-out work is distributed to multiple instances of the `F2` function. The The automatic checkpointing that happens at the `await` call on `Task.WhenAll` ensures that a potential midway crash or reboot doesn't require restarting an already completed task. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("FanOutFanIn")] +public static async Task Run( + [OrchestrationTrigger] TaskOrchestrationContext context) +{ + var parallelTasks = new List<Task<int>>(); ++ // Get a list of N work items to process in parallel. + object[] workBatch = await context.CallActivityAsync<object[]>("F1", null); + for (int i = 0; i < workBatch.Length; i++) + { + Task<int> task = context.CallActivityAsync<int>("F2", workBatch[i]); + parallelTasks.Add(task); + } ++ await Task.WhenAll(parallelTasks); ++ // Aggregate all N outputs and send the result to F3. + int sum = parallelTasks.Sum(t => t.Result); + await context.CallActivityAsync("F3", sum); +} +``` ++The fan-out work is distributed to multiple instances of the `F2` function. The work is tracked by using a dynamic list of tasks. `Task.WhenAll` is called to wait for all the called functions to finish. Then, the `F2` function outputs are aggregated from the dynamic task list and passed to the `F3` function. ++The automatic checkpointing that happens at the `await` call on `Task.WhenAll` ensures that a potential midway crash or reboot doesn't require restarting an already completed task. + # [JavaScript](#tab/javascript) ```javascript In a few lines of code, you can use Durable Functions to create multiple monitor The following code implements a basic monitor: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("MonitorJobStatus")] public static async Task Run( } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("MonitorJobStatus")] +public static async Task Run( + [OrchestrationTrigger] TaskOrchestrationContext context, int jobId) +{ + int pollingInterval = GetPollingInterval(); + DateTime expiryTime = GetExpiryTime(); ++ while (context.CurrentUtcDateTime < expiryTime) + { + var jobStatus = await context.CallActivityAsync<string>("GetJobStatus", jobId); + if (jobStatus == "Completed") + { + // Perform an action when a condition is met. + await context.CallActivityAsync("SendAlert", machineId); + break; + } ++ // Orchestration sleeps until this time. + var nextCheck = context.CurrentUtcDateTime.AddSeconds(pollingInterval); + await context.CreateTimer(nextCheck, CancellationToken.None); + } ++ // Perform more work here, or let the orchestration end. +} +``` + # [JavaScript](#tab/javascript) ```javascript You can implement the pattern in this example by using an orchestrator function. These examples create an approval process to demonstrate the human interaction pattern: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("ApprovalWorkflow")] public static async Task Run( To create the durable timer, call `context.CreateTimer`. The notification is received by `context.WaitForExternalEvent`. Then, `Task.WhenAny` is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout). +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("ApprovalWorkflow")] +public static async Task Run( + [OrchestrationTrigger] TaskOrchestrationContext context) +{ + await context.CallActivityAsync("RequestApproval", null); + using (var timeoutCts = new CancellationTokenSource()) + { + DateTime dueTime = context.CurrentUtcDateTime.AddHours(72); + Task durableTimeout = context.CreateTimer(dueTime, timeoutCts.Token); ++ Task<bool> approvalEvent = context.WaitForExternalEvent<bool>("ApprovalEvent"); + if (approvalEvent == await Task.WhenAny(approvalEvent, durableTimeout)) + { + timeoutCts.Cancel(); + await context.CallActivityAsync("ProcessApproval", approvalEvent.Result); + } + else + { + await context.CallActivityAsync("Escalate", null); + } + } +} +``` ++To create the durable timer, call `context.CreateTimer`. The notification is received by `context.WaitForExternalEvent`. Then, `Task.WhenAny` is called to decide whether to escalate (timeout happens first) or process the approval (the approval is received before timeout). + # [JavaScript](#tab/javascript) ```javascript curl -d "true" http://localhost:7071/runtime/webhooks/durabletask/instances/{ins An event can also be raised using the durable orchestration client from another function in the same function app: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("RaiseEventToOrchestration")] public static async Task Run( } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[Function("RaiseEventToOrchestration")] +public static async Task Run( + [HttpTrigger] string instanceId, + [DurableClient] DurableTaskClient client) +{ + bool isApproved = true; + await client.RaiseEventAsync(instanceId, "ApprovalEvent", isApproved); +} +``` + # [JavaScript](#tab/javascript) ```javascript The tricky thing about trying to implement this pattern with normal, stateless f You can use [Durable entities](durable-functions-entities.md) to easily implement this pattern as a single function. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("Counter")] public class Counter } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++Durable entities are currently not supported in the .NET-isolated worker. + # [JavaScript](#tab/javascript) ```javascript Durable entities are currently not supported in Java. Clients can enqueue *operations* for (also known as "signaling") an entity function using the [entity client binding](durable-functions-bindings.md#entity-client). -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-isolated) ```csharp [FunctionName("EventHubTriggerCSharp")] public static async Task Run( > [!NOTE] > Dynamically generated proxies are also available in .NET for signaling entities in a type-safe way. And in addition to signaling, clients can also query for the state of an entity function using [type-safe methods](durable-functions-dotnet-entities.md#accessing-entities-through-interfaces) on the orchestration client binding. +# [C# (Isolated)](#tab/csharp-inproc) ++Durable entities are currently not supported in the .NET-isolated worker. + # [JavaScript](#tab/javascript) ```javascript |
azure-functions | Durable Functions Serialization And Persistence | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-serialization-and-persistence.md | The Durable Functions runtime automatically persists function parameters, return Task hubs store the current state of instances, and any pending messages: -* *Instance states* store the current status and history of an instance. For orchestration instances, this includes the runtime state, the orchestration history, inputs, outputs, and custom status. For entity instances, it includes the entity state. -* *Messages* store function inputs or outputs, event payloads, and metadata that Durable Functions uses for internal purposes, like routing and end-to-end correlation. +* *Instance states* store the current status and history of an instance. For orchestration instances, this state includes the runtime state, the orchestration history, inputs, outputs, and custom status. For entity instances, it includes the entity state. +* *Messages* store function inputs or outputs, event payloads, and metadata that is used for internal purposes, like routing and end-to-end correlation. Messages are deleted after being processed, but instance states persist unless they're explicitly deleted by the application or an operator. In particular, an orchestration history remains in storage even after the orchestration completes. For an example of how states and messages represent the progress of an orchestration, see the [task hub execution example](durable-functions-task-hubs.md#execution-example). -Where and how states and messages are represented in storage [depends on the storage provider](durable-functions-task-hubs.md#representation-in-storage). By default, Durable Functions uses the [Azure Storage provider](durable-functions-azure-storage-provider.md) which persists data to queues, tables, and blobs in an [Azure Storage](https://azure.microsoft.com/services/storage/) account that you specify. +Where and how states and messages are represented in storage [depends on the storage provider](durable-functions-task-hubs.md#representation-in-storage). Durable Functions' default provider is [Azure Storage](durable-functions-azure-storage-provider.md), which persists data to queues, tables, and blobs in an [Azure Storage](https://azure.microsoft.com/services/storage/) account that you specify. ### Types of data that is serialized and persisted-The following is a list of the different types of data that will be serialized and persisted when using features of Durable Functions: +The following list shows the different types of data that will be serialized and persisted when using features of Durable Functions: - All inputs and outputs of orchestrator, activity, and entity functions, including any IDs and unhandled exceptions - Orchestrator, activity, and entity function names The following is a list of the different types of data that will be serialized a - Entity state payloads ### Working with sensitive data-When using Azure Storage, all data is automatically encrypted at rest. However, anyone with access to the storage account can read the data in its unencrypted form. If you need stronger protection for sensitive data, consider first encrypting the data using your own encryption keys so that Durable Functions persists the data in a pre-encrypted form. +When using the Azure Storage provider, all data is automatically encrypted at rest. However, anyone with access to the storage account can read the data in its unencrypted form. If you need stronger protection for sensitive data, consider first encrypting the data using your own encryption keys so that the data is persisted in its pre-encrypted form. Alternatively, .NET users have the option of implementing custom serialization providers that provide automatic encryption. An example of custom serialization with encryption can be found in [this GitHub sample](https://github.com/charleszipp/azure-durable-entities-encryption). Alternatively, .NET users have the option of implementing custom serialization p ## Customizing serialization and deserialization -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ### Default serialization logic -Durable Functions for .NET in-process internally uses [Json.NET](https://www.newtonsoft.com/json/help/html/Introduction.htm) to serialize orchestration and entity data to JSON. The default settings Durable Functions uses for Json.NET are: +Durable Functions for .NET in-process internally uses [Json.NET](https://www.newtonsoft.com/json/help/html/Introduction.htm) to serialize orchestration and entity data to JSON. The default Json.NET settings used are: **Inputs, Outputs, and State:** Read more detailed documentation about `JsonSerializerSettings` [here](https://w ## Customizing serialization with .NET attributes -When serializing data, Json.NET looks for [various attributes](https://www.newtonsoft.com/json/help/html/SerializationAttributes.htm) on classes and properties that control how the data is serialized and deserialized from JSON. If you own the source code for data type passed to Durable Functions APIs, consider adding these attributes to the type to customize serialization and deserialization. +During serialization, Json.NET looks for [various attributes](https://www.newtonsoft.com/json/help/html/SerializationAttributes.htm) on classes and properties that control how the data is serialized and deserialized from JSON. If you own the source code for data type passed to Durable Functions APIs, consider adding these attributes to the type to customize serialization and deserialization. ## Customizing serialization with Dependency Injection -Function apps that target .NET and run on the Functions V3 runtime can use [Dependency Injection (DI)](../functions-dotnet-dependency-injection.md) to customize how data and exceptions are serialized. The sample code below demonstrates how to use DI to override the default Json.NET serialization settings using custom implementations of the `IMessageSerializerSettingsFactory` and `IErrorSerializerSettingsFactory` service interfaces. +Function apps that target .NET and run on the Functions V3 runtime can use [Dependency Injection (DI)](../functions-dotnet-dependency-injection.md) to customize how data and exceptions are serialized. The following sample code demonstrates how to use DI to override the default Json.NET serialization settings using custom implementations of the `IMessageSerializerSettingsFactory` and `IErrorSerializerSettingsFactory` service interfaces. ```csharp using Microsoft.Azure.Functions.Extensions.DependencyInjection; namespace MyApplication } ``` +# [C# (Isolated)](#tab/csharp-isolated) ### .NET Isolated and System.Text.Json -Durable Functions running in the [.NET Isolated worker process](../dotnet-isolated-process-guide.md) use [System.Text.Json](/dotnet/api/system.text.json) libraries for serialization rather than Newtonsoft.Json. There is currently no support for injecting serialization settings. However, attributes may be used to control aspects of serialization. +Durable Functions running in the [.NET Isolated worker process](../dotnet-isolated-process-guide.md) uses the same object-serializer configured globally for your Azure Functions app (see [WorkerOptions](/dotnet/api/microsoft.azure.functions.worker.workeroptions)). This serializer happens to be [System.Text.Json](/dotnet/api/system.text.json) by default rather than Newtonsoft.Json. Any changes to `WorkerOptions.Serializer` will transitively apply to Durable Functions. For more information on the built-in support for JSON serialization in .NET, see the [JSON serialization and deserialization in .NET overview documentation](/dotnet/standard/serialization/system-text-json-overview). For full customization of the serialization/deserialization pipeline, consider h ### Serialization and deserialization logic -It is strongly recommended to use type annotations to ensure Durable Functions serializes and deserializes your data correctly. While many built-in types are handled automatically, some built-in data types require type annotations to preserve the type during deserialization. +It's recommended to use type annotations to ensure Durable Functions serializes and deserializes your data correctly. While many built-in types are handled automatically, some built-in data types require type annotations to preserve the type during deserialization. For custom data types, you must define the JSON serialization and deserialization of a data type by exporting a static `to_json` and `from_json` method from your class. |
azure-functions | Durable Functions Sub Orchestrations | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-sub-orchestrations.md | Sub-orchestrator functions behave just like activity functions from the caller's The following example illustrates an IoT ("Internet of Things") scenario where there are multiple devices that need to be provisioned. The following function represents the provisioning workflow that needs to be executed for each device: -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp public static async Task DeviceProvisioningOrchestration( public static async Task DeviceProvisioningOrchestration( } ``` +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +public static async Task DeviceProvisioningOrchestration( + [OrchestrationTrigger] TaskOrchestrationContext context, string deviceId) +{ + // Step 1: Create an installation package in blob storage and return a SAS URL. + Uri sasUrl = await context.CallActivityAsync<Uri>("CreateInstallationPackage", deviceId); ++ // Step 2: Notify the device that the installation package is ready. + await context.CallActivityAsync("SendPackageUrlToDevice", (deviceId, sasUrl)); ++ // Step 3: Wait for the device to acknowledge that it has downloaded the new package. + await context.WaitForExternalEvent<bool>("DownloadCompletedAck"); ++ // Step 4: ... +} +``` + # [JavaScript](#tab/javascript) ```javascript This orchestrator function can be used as-is for one-off device provisioning or Here is an example that shows how to run multiple orchestrator functions in parallel. -# [C#](#tab/csharp) +# [C# (InProc)](#tab/csharp-inproc) ```csharp [FunctionName("ProvisionNewDevices")] public static async Task ProvisionNewDevices( > [!NOTE] > The previous C# examples are for Durable Functions 2.x. For Durable Functions 1.x, you must use `DurableOrchestrationContext` instead of `IDurableOrchestrationContext`. For more information about the differences between versions, see the [Durable Functions versions](durable-functions-versions.md) article. +# [C# (Isolated)](#tab/csharp-isolated) ++```csharp +[FunctionName("ProvisionNewDevices")] +public static async Task ProvisionNewDevices( + [OrchestrationTrigger] TaskOrchestrationContext context) +{ + string[] deviceIds = await context.CallActivityAsync<string[]>("GetNewDeviceIds"); ++ // Run multiple device provisioning flows in parallel + var provisioningTasks = new List<Task>(); + foreach (string deviceId in deviceIds) + { + Task provisionTask = context.CallSubOrchestratorAsync("DeviceProvisioningOrchestration", deviceId); + provisioningTasks.Add(provisionTask); + } ++ await Task.WhenAll(provisioningTasks); ++ // ... +} +``` + # [JavaScript](#tab/javascript) ```javascript module.exports = df.orchestrator(function*(context) { }); ``` - # [Python](#tab/python) ```Python |
azure-functions | Durable Functions Versions | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/durable/durable-functions-versions.md | +> [!NOTE] +> This section does not apply to Durable Functions in dotnet isolated worker. For that, see [durable functions isolated process overview](./durable-functions-dotnet-isolated-overview.md). + ### Durable entities In Durable Functions 2.x, we introduced a new [entity functions](durable-functions-entities.md) concept. |
azure-functions | Functions Bindings Triggers Python | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/functions-bindings-triggers-python.md | To create your first function in the new v2 model, see one of these quickstart a + [Get started with Visual Studio](./create-first-function-vs-code-python.md) + [Get started command prompt](./create-first-function-cli-python.md) -## Blob trigger +## Azure Blob storage trigger The following code snippet defines a function triggered from Azure Blob Storage: import azure.functions as func app = func.FunctionApp() @app.function_name(name="BlobTrigger1") @app.blob_trigger(arg_name="myblob", path="samples-workitems/{name}",- connection="<STORAGE_CONNECTION_SETTING>") + connection="AzureWebJobsStorage") def test_function(myblob: func.InputStream): logging.info(f"Python blob trigger function processed blob \n" f"Name: {myblob.name}\n" f"Blob Size: {myblob.length} bytes") ``` +## Azure Blob storage input binding ++```python +import logging +import azure.functions as func +app = func.FunctionApp() +@app.function_name(name="BlobInput1") +@app.route(route="file") +@app.blob_input(arg_name="inputblob", + path="sample-workitems/{name}", + connection="AzureWebJobsStorage") +def test(req: func.HttpRequest, inputblob: bytes) -> func.HttpResponse: + logging.info(f'Python Queue trigger function processed {len(inputblob)} bytes') + return inputblob +``` ++## Azure Blob storage output binding ++```python +import logging +import azure.functions as func +app = func.FunctionApp() +@app.function_name(name="BlobOutput1") +@app.route(route="file") +@app.blob_input(arg_name="inputblob", + path="sample-workitems/test.txt", + connection="AzureWebJobsStorage") +@app.blob_output(arg_name="outputblob", + path="newblob/test.txt", + connection="AzureWebJobsStorage") +def main(req: func.HttpRequest, inputblob: str, outputblob: func.Out[str]): + logging.info(f'Python Queue trigger function processed {len(inputblob)} bytes') + outputblob.set(inputblob) + return "ok" +``` + ## Azure Cosmos DB trigger The following code snippet defines a function triggered from an Azure Cosmos DB (SQL API): import logging import azure.functions as func app = func.FunctionApp() @app.function_name(name="CosmosDBTrigger1")-@app.cosmos_db_trigger(arg_name="documents", database_name="<DB_NAME>", collection_name="<COLLECTION_NAME>", connection_string_setting="<COSMOS_CONNECTION_SETTING>", +@app.cosmos_db_trigger(arg_name="documents", database_name="<DB_NAME>", collection_name="<COLLECTION_NAME>", connection_string_setting=""AzureWebJobsStorage"", lease_collection_name="leases", create_lease_collection_if_not_exists="true") def test_function(documents: func.DocumentList) -> str: if documents: logging.info('Document id: %s', documents[0]['id']) ``` +## Azure Cosmos DB input binding ++```python +import logging +import azure.functions as func +app = func.FunctionApp() +@app.route() +@app.cosmos_db_input( + arg_name="documents", database_name="<DB_NAME>", + collection_name="<COLLECTION_NAME>", + connection_string_setting="CONNECTION_SETTING") +def cosmosdb_input(req: func.HttpRequest, documents: func.DocumentList) -> str: + return func.HttpResponse(documents[0].to_json()) +``` ++## Azure Cosmos DB output binding ++```python +import logging +import azure.functions as func +@app.route() +@app.cosmos_db_output( + arg_name="documents", database_name="<DB_NAME>", + collection_name="<COLLECTION_NAME>", + create_if_not_exists=True, + connection_string_setting="CONNECTION_SETTING") +def main(req: func.HttpRequest, documents: func.Out[func.Document]) -> func.HttpResponse: + request_body = req.get_body() + documents.set(func.Document.from_json(request_body)) + return 'OK' +``` + ## Azure EventHub trigger The following code snippet defines a function triggered from an event hub instance: import azure.functions as func app = func.FunctionApp() @app.function_name(name="EventHubTrigger1") @app.event_hub_message_trigger(arg_name="myhub", event_hub_name="samples-workitems",- connection="<EVENT_HUB_CONNECTION_SETTING>") + connection=""CONNECTION_SETTING"") def test_function(myhub: func.EventHubEvent): logging.info('Python EventHub trigger processed an event: %s', myhub.get_body().decode('utf-8')) ``` +## Azure EventHub output binding ++```python +import logging +import azure.functions as func +app = func.FunctionApp() +@app.function_name(name="eventhub_output") +@app.route(route="eventhub_output") +@app.event_hub_output(arg_name="event", + event_hub_name="samples-workitems", + connection="CONNECTION_SETTING") +def eventhub_output(req: func.HttpRequest, event: func.Out[str]): + body = req.get_body() + if body is not None: + event.set(body.decode('utf-8')) + else: + logging.info('req body is none') + return 'ok' +``` + ## HTTP trigger The following code snippet defines an HTTP triggered function: def test_function(req: func.HttpRequest) -> func.HttpResponse: ) ``` -## Azure Queue Storage trigger +## Azure Queue storage trigger ```python import logging import azure.functions as func app = func.FunctionApp() @app.function_name(name="QueueTrigger1") @app.queue_trigger(arg_name="msg", queue_name="python-queue-items",- connection="") + connection=""AzureWebJobsStorage"") def test_function(msg: func.QueueMessage): logging.info('Python EventHub trigger processed an event: %s', msg.get_body().decode('utf-8')) ``` +## Azure Queue storage output binding ++```python +import logging +import azure.functions as func +app = func.FunctionApp() +@app.function_name(name="QueueOutput1") +@app.route(route="message") +@app.queue_output(arg_name="msg", queue_name="python-queue-items", connection="AzureWebJobsStorage") +def main(req: func.HttpRequest, msg: func.Out[str]) -> func.HttpResponse: + input_msg = req.params.get('name') + msg.set(input_msg) + logging.info(input_msg) + logging.info('name: {name}') + return 'OK' +``` + ## Azure Service Bus queue trigger ```python import logging import azure.functions as func app = func.FunctionApp() @app.function_name(name="ServiceBusQueueTrigger1")-@app.service_bus_queue_trigger(arg_name="msg", queue_name="myinputqueue", connection="") +@app.service_bus_queue_trigger(arg_name="msg", queue_name="myinputqueue", connection="CONNECTION_SETTING") def test_function(msg: func.ServiceBusMessage): logging.info('Python ServiceBus queue trigger processed message: %s', msg.get_body().decode('utf-8')) import logging import azure.functions as func app = func.FunctionApp() @app.function_name(name="ServiceBusTopicTrigger1")-@app.service_bus_topic_trigger(arg_name="message", topic_name="mytopic", connection="", subscription_name="testsub") +@app.service_bus_topic_trigger(arg_name="message", topic_name="mytopic", connection="CONNECTION_SETTING", subscription_name="testsub") def test_function(message: func.ServiceBusMessage): message_body = message.get_body().decode("utf-8") logging.info("Python ServiceBus topic trigger processed message.") logging.info("Message Body: " + message_body) ``` +## Azure Service Bus Topic output binding ++```python +import logging +import azure.functions as func +app = func.FunctionApp() +@app.route(route="put_message") +@app.service_bus_topic_output( + arg_name="message", + connection="CONNECTION_SETTING", + topic_name="mytopic") +def main(req: func.HttpRequest, message: func.Out[str]) -> func.HttpResponse: + input_msg = req.params.get('message') + message.set(input_msg) + return 'OK' +``` + ## Timer trigger ```python |
azure-functions | Functions Move Across Regions | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/functions-move-across-regions.md | Review and configure the resources identified in the [Prepare](#prepare) step ab + Function app names are globally unique in Azure, so the app in the target region can't have the same name as the one in the source region + References and application settings that connect your function app to dependencies need to be reviewed and, when needed, updated. For example, when you move a database that your functions call, you must also update the application settings or configuration to connect to the database in the target region. Some application settings such as the Application Insights instrumentation key or the Azure storage account used by the function app can be already be configured on the target region and do not need to be updated + Remember to verify your configuration and test your functions in the target region-+ If you had custom domain configured, [remap the domain name](../app-service/manage-custom-dns-migrate-domain.md#remap-the-active-dns-name) ++ If you had custom domain configured, [remap the domain name](../app-service/manage-custom-dns-migrate-domain.md#4-remap-the-active-dns-name) + For Functions running on Dedicated plans also review the [App Service Migration Plan](../app-service/manage-move-across-regions.md) in case the plan is shared with web apps ## Clean up source resources |
azure-functions | Functions Reference Python | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/functions-reference-python.md | At this time, only specific triggers and bindings are supported by the Python v2 | [Azure Service Bus topic](functions-bindings-triggers-python.md#azure-service-bus-topic-trigger) | x | | x | | [Azure Service Bus queue](functions-bindings-triggers-python.md#azure-service-bus-queue-trigger) | x | | x | | [Azure Cosmos DB](functions-bindings-triggers-python.md#azure-eventhub-trigger) | x | x | x |-| [Azure Blob Storage](functions-bindings-triggers-python.md#blob-trigger) | x | x | x | +| [Azure Blob Storage](functions-bindings-triggers-python.md#azure-blob-storage-trigger) | x | x | x | | [Azure Hub](functions-bindings-triggers-python.md#azure-eventhub-trigger) | x | | x | For more examples, see [Python V2 model Azure Functions triggers and bindings (preview)](functions-bindings-triggers-python.md). |
azure-functions | Functions Run Local | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-functions/functions-run-local.md | There are no additional considerations for PowerShell. # [TypeScript](#tab/ts) -+ To use a `--worker-runtime` value of `node`, specify the `--language` as `javascript`. ++ To use a `--worker-runtime` value of `node`, specify the `--language` as `typescript`. + See the [TypeScript section in the JavaScript developer reference](functions-reference-node.md#typescript) for `func init` behaviors specific to TypeScript. |
azure-government | Documentation Government Csp List | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-government/documentation-government-csp-list.md | Below you can find a list of all the authorized Cloud Solution Providers (CSPs), |[3Di inc](https://www.3disystems.com)| |[AC4S Consulting, Inc.](https://ac4s.com)| |[Accelera Solutions Inc](http://www.accelerasolutions.com/)|-|[Accenture Federal Services LLC](https://www.accenture.com/us-en/afs-industry-index)| +|[Accenture Federal Services LLC](https://www.accenture.com/us-en/industries/afs-index)| |[Access Interactive Inc.](https://www.access-interactive.com/)| |[AccountabilIT](https://accountabilit.com)| |[ACP Technologies](https://acp.us.com)| |
azure-maps | Release Notes Map Control | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-maps/release-notes-map-control.md | -## [3.0.0-preview.2](https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.2) (December 16, 2022) +## v3 (preview) -### New features +### [3.0.0-preview.3] (February 2, 2023) -Add `progressiveLoading` and `progressiveLoadingInitialLayerGroups` to [StyleOptions][StyleOptions] to enable the capability of loading map layers progressively. This feature improves the perceived loading time of the map. For more information, see [2.2.2 release notes](#222-december-15-2022). +#### Installation (3.0.0-preview.3) -The preview is available on [npm](https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.2) and CDN. +The preview is available on [npm][3.0.0-preview.3] and CDN. - - Install [azure-maps-control@next][azure-maps-control] to your dependencies: - ```shell - npm i azure-maps-control@next - ``` +- **NPM:** Refer to the instructions at [azure-maps-control@3.0.0-preview.3][3.0.0-preview.3] ++- **CDN:** Reference the following CSS and JavaScript in the `<head>` element of an HTML file: - - Reference the following CSS and JavaScript in the `<head>` element of an HTML file: ```html- <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3.0.0-preview.2/atlas.min.css" rel="stylesheet" /> - <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3.0.0-preview.2/atlas.min.js"></script> + <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3.0.0-preview.3/atlas.min.css" rel="stylesheet" /> + <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3.0.0-preview.3/atlas.min.js"></script> + ``` ++#### New features (3.0.0-preview.3) ++- **\[BREAKING\]** Migrated from [adal-angular] to [@azure/msal-browser] used for authentication with Microsoft Azure Active Directory ([Azure AD]). + Changes that may be required: + - `Platform / Reply URL` Type must be set to `Single-page application` on Azure AD App Registration portal. + - Code change is required if a custom `authOptions.authContext` is used. + - For more information, see [How to migrate a JavaScript app from ADAL.js to MSAL.js][migration guide]. ++- Allow pitch and bearing being set with [CameraBoundsOptions] in [Map.setCamera(options)]. ++#### Bug fixes (3.0.0-preview.3) ++- Fixed issue in [language mapping], now `zh-Hant-TW` will no longer revert back to `en-US`. ++- Fixed the inability to switch between [user regions (view)]. ++- Fixed exception that occurred when style switching while progressive layer loading is in progress. ++- Fixed the accessibility information retrieval from map tile label layers. ++- Fixed the occasional issue where vector tiles aren't being rerendered after images are being added via [ImageSpriteManager.add()]. ++### [3.0.0-preview.2] (December 16, 2022) ++#### Installation (3.0.0-preview.2) ++The preview is available on [npm][3.0.0-preview.2] and CDN. ++- **NPM:** Refer to the instructions at [azure-maps-control@3.0.0-preview.2][3.0.0-preview.2] ++- **CDN:** Reference the following CSS and JavaScript in the `<head>` element of an HTML file: ++ ```html + <link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3.0.0-preview.2/atlas.min.css" rel="stylesheet" /> + <script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3.0.0-preview.2/atlas.min.js"></script> ``` -### Bug fixes +#### New features (3.0.0-preview.2) -- Fix an issue that the ordering of user layers wasn't preserved after calling `map.layers.move()`.+Add `progressiveLoading` and `progressiveLoadingInitialLayerGroups` to [StyleOptions] to enable the capability of loading map layers progressively. This feature improves the perceived loading time of the map. For more information, see [2.2.2 release notes](#222-december-15-2022). -- Fix the inability to disable traffic incidents in [TrafficControlOptions][TrafficControlOptions] when `new atlas.control.TrafficControl({incidents: false})` is used. +#### Bug fixes (3.0.0-preview.2) ++- Fixed an issue that the ordering of user layers wasn't preserved after calling `map.layers.move()`. ++- Fixed the inability to disable traffic incidents in [TrafficControlOptions] when `new atlas.control.TrafficControl({incidents: false})` is used. - Add `.atlas-map` to all css selectors to scope the styles within the map container. The fix prevents the css from accidentally adding unwanted styles to other elements on the page. -## [3.0.0-preview.1](https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.1) (November 18, 2022) +### [3.0.0-preview.1] (November 18, 2022) ++### Installation (3.0.0-preview.1) -### New features +The preview is available on [npm][3.0.0-preview.1]. -This update is the first preview of the upcoming 3.0.0 release. The underlying [maplibre-gl][maplibre-gl] dependency has been upgraded from `1.14` to `3.0.0-pre.1`, offering improvements in stability and performance. The preview is available on [npm](https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.1). +- Install [azure-maps-control@next][azure-maps-control] to your dependencies: - - Install [azure-maps-control@next][azure-maps-control] to your dependencies: ```shell npm i azure-maps-control@next ``` -### Bug fixes +#### New features (3.0.0-preview.1) -- Fix a regression issue that prevents IndoorManager from removing a tileset by using- ```js - indoorManager.setOptions({ - tilesetId: undefined - }) - ``` +This update is the first preview of the upcoming 3.0.0 release. The underlying [maplibre-gl] dependency has been upgraded from `1.14` to `3.0.0-pre.1`, offering improvements in stability and performance. ++#### Bug fixes (3.0.0-preview.1) ++- Fixed a regression issue that prevents IndoorManager from removing a tileset: ++ ```js + indoorManager.setOptions({ + tilesetId: undefined + }) + ``` ++## v2 (latest) ++### [2.2.3] ++#### New features (2.2.3) -## [2.2.2](https://www.npmjs.com/package/azure-maps-control/v/2.2.2) (December 15, 2022) +- Allow pitch and bearing being set with [CameraBoundsOptions] in [Map.setCamera(options)]. -### New features +#### Bug fixes (2.2.3) ++- Fixed issue in [language mapping], now `zh-Hant-TW` will no longer revert back to `en-US`. ++- Fixed the inability to switch between [user regions (view)]. ++- Fixed exception that occurred when style switching while progressive layer loading is in progress. ++- Fixed the accessibility information retrieval from map tile label layers. ++- Fixed the occasional issue where vector tiles aren't being rerendered after images are being added via [ImageSpriteManager.add()]. ++### [2.2.2] (December 15, 2022) ++#### New features (2.2.2) ++Add `progressiveLoading` and `progressiveLoadingInitialLayerGroups` to [StyleOptions] to enable the capability of loading map layers progressively. This feature improves the perceived loading time of the map. -Add `progressiveLoading` and `progressiveLoadingInitialLayerGroups` to [StyleOptions][StyleOptions] to enable the capability of loading map layers progressively. This feature improves the perceived loading time of the map. - `progressiveLoading` - Enables progressive loading of map layers. - Defaults to `false`. Add `progressiveLoading` and `progressiveLoadingInitialLayerGroups` to [StyleOpt - Possible values are `base`, `transit`, `labels`, `buildings`, and `labels_places`. - Other layer groups are deferred such that the initial layer groups can be loaded first. -### Bug fixes +#### Bug fixes (2.2.2) -- Fix an issue that the ordering of user layers wasn't preserved after calling `map.layers.move()`.+- Fixed an issue that the ordering of user layers wasn't preserved after calling `map.layers.move()`. -- Fix the inability to disable traffic incidents in [TrafficControlOptions][TrafficControlOptions] when `new atlas.control.TrafficControl({incidents: false})` is used. +- Fixed the inability to disable traffic incidents in [TrafficControlOptions] when `new atlas.control.TrafficControl({incidents: false})` is used. ## Next steps Explore samples showcasing Azure Maps: -[Azure Maps Samples](https://samples.azuremaps.com) +> [!div class="nextstepaction"] +> [Azure Maps Samples] Stay up to date on Azure Maps: -[Azure Maps Blog](https://techcommunity.microsoft.com/t5/azure-maps-blog/bg-p/AzureMapsBlog) -+> [!div class="nextstepaction"] +> [Azure Maps Blog] ++[3.0.0-preview.3]: https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.3 +[3.0.0-preview.2]: https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.2 +[3.0.0-preview.1]: https://www.npmjs.com/package/azure-maps-control/v/3.0.0-preview.1 +[2.2.3]: https://www.npmjs.com/package/azure-maps-control/v/2.2.3 +[2.2.2]: https://www.npmjs.com/package/azure-maps-control/v/2.2.2 +[Azure AD]: /azure/active-directory/develop/v2-overview +[adal-angular]: https://github.com/AzureAD/azure-activedirectory-library-for-js +[@azure/msal-browser]: https://github.com/AzureAD/microsoft-authentication-library-for-js +[migration guide]: /azure/active-directory/develop/msal-compare-msal-js-and-adal-js +[CameraBoundsOptions]: /javascript/api/azure-maps-control/atlas.cameraboundsoptions?view=azure-maps-typescript-latest +[Map.setCamera(options)]: /javascript/api/azure-maps-control/atlas.map?view=azure-maps-typescript-latest#azure-maps-control-atlas-map-setcamera +[language mapping]: https://github.com/MicrosoftDocs/azure-docs/blob/main/articles/azure-maps/supported-languages.md#azure-maps-supported-languages +[user regions (view)]: /javascript/api/azure-maps-control/atlas.styleoptions?view=azure-maps-typescript-latest#azure-maps-control-atlas-styleoptions-view +[ImageSpriteManager.add()]: /javascript/api/azure-maps-control/atlas.imagespritemanager?view=azure-maps-typescript-latest#azure-maps-control-atlas-imagespritemanager-add [azure-maps-control]: https://www.npmjs.com/package/azure-maps-control [maplibre-gl]: https://www.npmjs.com/package/maplibre-gl [StyleOptions]: /javascript/api/azure-maps-control/atlas.styleoptions-[TrafficControlOptions]: /javascript/api/azure-maps-control/atlas.trafficcontroloptions +[TrafficControlOptions]: /javascript/api/azure-maps-control/atlas.trafficcontroloptions +[Azure Maps Samples]: https://samples.azuremaps.com +[Azure Maps Blog]: https://techcommunity.microsoft.com/t5/azure-maps-blog/bg-p/AzureMapsBlog |
azure-monitor | Agent Linux | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-monitor/agents/agent-linux.md | -# Install Log Analytics agent on Linux computers +# Install the Log Analytics agent on Linux computers This article provides details on installing the Log Analytics agent on Linux computers hosted in other clouds or on-premises. [!INCLUDE [Log Analytics agent deprecation](../../../includes/log-analytics-agent-deprecation.md)] The [installation methods described in this article](#install-the-agent) are: -* Install the agent for Linux using a wrapper-script hosted on GitHub. This is the recommended method to install and upgrade the agent when the computer has connectivity with the Internet, directly or through a proxy server. -* Manually download and install the agent. This is required when the Linux computer doesn't have access to the Internet and will be communicating with Azure Monitor or Azure Automation through the [Log Analytics gateway](./gateway.md). +* Install the agent for Linux by using a wrapper-script hosted on GitHub. We recommend this method to install and upgrade the agent when the computer has connectivity with the internet, either directly or through a proxy server. +* Manually download and install the agent. This step is required when the Linux computer doesn't have access to the internet and will be communicating with Azure Monitor or Azure Automation through the [Log Analytics gateway](./gateway.md). -See [Installation options](./log-analytics-agent.md#installation-options) for more efficient options you can use for Azure virtual machines. +For more efficient options that you can use for Azure virtual machines, see [Installation options](./log-analytics-agent.md#installation-options). ## Requirements +The following sections outline the requirements for installation. + ### Supported operating systems -See [Overview of Azure Monitor agents](agents-overview.md#supported-operating-systems) for a list of Linux distributions supported by the Log Analytics agent. +For a list of Linux distributions supported by the Log Analytics agent, see [Overview of Azure Monitor agents](agents-overview.md#supported-operating-systems). ->[!NOTE] ->OpenSSL 1.1.0 is only supported on x86_x64 platforms (64-bit) and OpenSSL earlier than 1.x is not supported on any platform. +OpenSSL 1.1.0 is only supported on x86_x64 platforms (64-bit). OpenSSL earlier than 1.x isn't supported on any platform. >[!NOTE]->The Log Analytics Linux Agent does not run in containers. To monitor containers, use the [Container Monitoring solution](../containers/containers.md) for Docker hosts or [Container insights](../containers/container-insights-overview.md) for Kubernetes. +>The Log Analytics Linux agent doesn't run in containers. To monitor containers, use the [Container Monitoring solution](../containers/containers.md) for Docker hosts or [Container insights](../containers/container-insights-overview.md) for Kubernetes. Starting with versions released after August 2018, we're making the following changes to our support model: -* Only the server versions are supported, not client. -* Focus support on any of the [Azure Linux Endorsed distros](../../virtual-machines/linux/endorsed-distros.md). There may be some delay between a new distro/version being Azure Linux Endorsed and it being supported for the Log Analytics Linux agent. +* Only the server versions are supported, not the client versions. +* Focus support on any of the [Azure Linux Endorsed distros](../../virtual-machines/linux/endorsed-distros.md). There might be some delay between a new distro/version being Azure Linux Endorsed and it being supported for the Log Analytics Linux agent. * All minor releases are supported for each major version listed. * Versions that have passed their manufacturer's end-of-support date aren't supported.-* Only support VM images; containers, even those derived from official distro publishers' images, aren't supported. +* Only support VM images. Containers aren't supported, even those derived from official distro publishers' images. * New versions of AMI aren't supported. * Only versions that run OpenSSL 1.x by default are supported. >[!NOTE]->If you are using a distro or version that is not currently supported and doesn't align to our support model, we recommend that you fork this repo, acknowledging that Microsoft support will not provide assistance with forked agent versions. +>If you're using a distro or version that isn't currently supported and doesn't align to our support model, we recommend that you fork this repo. Acknowledge that Microsoft support won't provide assistance with forked agent versions. ### Python requirement -Starting from Agent version 1.13.27, the Linux Agent will support both Python 2 and 3. We always recommend using the latest agent. +Starting from agent version 1.13.27, the Linux agent will support both Python 2 and 3. We always recommend that you use the latest agent. -If you're using an older version of the agent, you must have the Virtual Machine use Python 2 by default. If your virtual machine is using a distro that doesn't include Python 2 by default, then you must install it. The following sample commands will install Python 2 on different distros. +If you're using an older version of the agent, you must have the virtual machine use Python 2 by default. If your virtual machine is using a distro that doesn't include Python 2 by default, then you must install it. The following sample commands will install Python 2 on different distros: + - **Red Hat, CentOS, Oracle**: `yum install -y python2` + - **Ubuntu, Debian**: `apt-get install -y python2` + - **SUSE**: `zypper install -y python2` -Again, only if you're using an older version of the agent, the python2 executable must be aliased to *python*. Following is one method that you can use to set this alias: +Again, only if you're using an older version of the agent, the python2 executable must be aliased to *python*. Use the following method to set this alias: -1. Run the following command to remove any existing aliases. +1. Run the following command to remove any existing aliases: ``` sudo update-alternatives --remove-all python ``` -2. Run the following command to create the alias. +1. Run the following command to create the alias: ``` sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 1 Again, only if you're using an older version of the agent, the python2 executabl ### Supported Linux hardening The OMS Agent has limited customization and hardening support for Linux. -The following are currently supported: +The following tools are currently supported: - SELinux (Marketplace images for CentOS and RHEL with their default settings) - FIPS (Marketplace images for CentOS and RHEL 6/7 with their default settings) -The following aren't supported: +The following tools aren't supported: - CIS - SELinux (custom hardening like MLS) -CIS, FIPS and SELinux hardening support is planned for [Azure Monitoring Agent](./azure-monitor-agent-overview.md). Further hardening and customization methods aren't supported nor planned for OMS Agent. For instance, OS images like GitHub Enterprise Server which include customizations such as limitations to user account privileges aren't supported. +CIS, FIPS, and SELinux hardening support is planned for [Azure Monitor Agent](./azure-monitor-agent-overview.md). Further hardening and customization methods aren't supported or planned for OMS Agent. For instance, OS images like GitHub Enterprise Server, which include customizations such as limitations to user account privileges, aren't supported. ### Agent prerequisites -The following table highlights the packages required for [supported Linux distros](#supported-operating-systems) that the agent will be installed on. +The following table highlights the packages required for [supported Linux distros](#supported-operating-systems) on which the agent will be installed. |Required package |Description |Minimum version | |--||-|-|Glibc | GNU C Library | 2.5-12 -|Openssl | OpenSSL Libraries | 1.0.x or 1.1.x | +|Glibc | GNU C library | 2.5-12 +|Openssl | OpenSSL libraries | 1.0.x or 1.1.x | |Curl | cURL web client | 7.15.5 | |Python | | 2.7 or 3.6+ |Python-ctypes | | -|PAM | Pluggable Authentication Modules | | +|PAM | Pluggable authentication modules | | >[!NOTE]->Either rsyslog or syslog-ng are required to collect syslog messages. The default syslog daemon on version 5 of Red Hat Enterprise Linux, CentOS, and Oracle Linux version (sysklog) is not supported for syslog event collection. To collect syslog data from this version of these distributions, the rsyslog daemon should be installed and configured to replace sysklog. +>Either rsyslog or syslog-ng is required to collect syslog messages. The default syslog daemon on version 5 of Red Hat Enterprise Linux, CentOS, and Oracle Linux version (sysklog) isn't supported for syslog event collection. To collect syslog data from this version of these distributions, the rsyslog daemon should be installed and configured to replace sysklog. ### Network requirements-See [Log Analytics agent overview](./log-analytics-agent.md#network-requirements) for the network requirements for the Linux agent. +For the network requirements for the Linux agent, see [Log Analytics agent overview](./log-analytics-agent.md#network-requirements). ### Workspace ID and key -Regardless of the installation method used, you'll require the workspace ID and key for the Log Analytics workspace that the agent will connect to. Select the workspace from the **Log Analytics workspaces** menu in the Azure portal. Then select **Agents management** in the **Settings** section. +Regardless of the installation method used, you need the workspace ID and key for the Log Analytics workspace that the agent will connect to. Select the workspace from the **Log Analytics workspaces** menu in the Azure portal. Under the **Settings** section, select **Agents management**. -[](media/log-analytics-agent/workspace-details.png#lightbox) +[](media/log-analytics-agent/workspace-details.png#lightbox) ## Agent install package The Log Analytics agent for Linux is composed of multiple packages. The release file contains the following packages, which are available by running the shell bundle with the `--extract` parameter: -**Package** | **Version** | **Description** +Package | Version | Description -- | -- | ---omsagent | 1.14.19 | The Log Analytics Agent for Linux -omsconfig | 1.1.1 | Configuration agent for the Log Analytics agent -omi | 1.6.9 | Open Management Infrastructure (OMI) -- a lightweight CIM Server. *Note that OMI requires root access to run a cron job necessary for the functioning of the service* -scx | 1.6.9 | OMI CIM Providers for operating system performance metrics +omsagent | 1.14.19 | The Log Analytics agent for Linux. +omsconfig | 1.1.1 | Configuration agent for the Log Analytics agent. +omi | 1.6.9 | Open Management Infrastructure (OMI), a lightweight CIM Server. *OMI requires root access to run a cron job necessary for the functioning of the service*. +scx | 1.6.9 | OMI CIM providers for operating system performance metrics. apache-cimprov | 1.0.1 | Apache HTTP Server performance monitoring provider for OMI. Only installed if Apache HTTP Server is detected. mysql-cimprov | 1.0.1 | MySQL Server performance monitoring provider for OMI. Only installed if MySQL/MariaDB server is detected. docker-cimprov | 1.0.0 | Docker provider for OMI. Only installed if Docker is detected. docker-cimprov | 1.0.0 | Docker provider for OMI. Only installed if Docker is de [!INCLUDE [Log Analytics agent deprecation](../../../includes/log-analytics-agent-deprecation.md)] -Installing the Log Analytics agent for Linux packages also applies the system-wide configuration changes below. Uninstalling the omsagent package removes these artifacts. +Installing the Log Analytics agent for Linux packages also applies the following systemwide configuration changes. Uninstalling the omsagent package removes these artifacts. -* A non-privileged user named: `omsagent` is created. The daemon runs under this credential. -* A sudoers *include* file is created in `/etc/sudoers.d/omsagent`. This authorizes `omsagent` to restart the syslog and omsagent daemons. If sudo *include* directives aren't supported in the installed version of sudo, these entries will be written to `/etc/sudoers`. +* A non-privileged user named `omsagent` is created. The daemon runs under this credential. +* A sudoers *include* file is created in `/etc/sudoers.d/omsagent`. This file authorizes `omsagent` to restart the syslog and omsagent daemons. If sudo *include* directives aren't supported in the installed version of sudo, these entries will be written to `/etc/sudoers`. * The syslog configuration is modified to forward a subset of events to the agent. For more information, see [Configure Syslog data collection](data-sources-syslog.md). -On a monitored Linux computer, the agent is listed as `omsagent`. `omsconfig` is the Log Analytics agent for Linux configuration agent that looks for new portal side configuration every 5 minutes. The new and updated configuration is applied to the agent configuration files located at `/etc/opt/microsoft/omsagent/conf/omsagent.conf`. +On a monitored Linux computer, the agent is listed as `omsagent`. `omsconfig` is the Log Analytics agent for the Linux configuration agent that looks for new portal-side configuration every 5 minutes. The new and updated configuration is applied to the agent configuration files located at `/etc/opt/microsoft/omsagent/conf/omsagent.conf`. -## Install the agent +## Install the agent [!INCLUDE [Log Analytics agent deprecation](../../../includes/log-analytics-agent-deprecation.md)] ### [Wrapper script](#tab/wrapper-script) -The following steps configure setup of the agent for Log Analytics in Azure and Azure Government cloud using the wrapper script for Linux computers that can communicate directly or through a proxy server to download the agent hosted on GitHub and install the agent. +The following steps configure setup of the agent for Log Analytics in Azure and Azure Government cloud. A wrapper script is used for Linux computers that can communicate directly or through a proxy server to download the agent hosted on GitHub and install the agent. -If your Linux computer needs to communicate through a proxy server to Log Analytics, this configuration can be specified on the command line by including `-p [protocol://][user:password@]proxyhost[:port]`. The *protocol* property accepts `http` or `https`, and the *proxyhost* property accepts a fully qualified domain name or IP address of the proxy server. +If your Linux computer needs to communicate through a proxy server to Log Analytics, this configuration can be specified on the command line by including `-p [protocol://][user:password@]proxyhost[:port]`. The `protocol` property accepts `http` or `https`. The `proxyhost` property accepts a fully qualified domain name or IP address of the proxy server. For example: `https://proxy01.contoso.com:30443` -If authentication is required in either case, you need to specify the username and password. For example: `https://user01:password@proxy01.contoso.com:30443` +If authentication is required in either case, specify the username and password. For example: `https://user01:password@proxy01.contoso.com:30443` -1. To configure the Linux computer to connect to a Log Analytics workspace, run the following command providing the workspace ID and primary key. The following command downloads the agent, validates its checksum, and installs it. +1. To configure the Linux computer to connect to a Log Analytics workspace, run the following command that provides the workspace ID and primary key. The following command downloads the agent, validates its checksum, and installs it. ``` wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh && sh onboard_agent.sh -w <YOUR WORKSPACE ID> -s <YOUR WORKSPACE PRIMARY KEY> If authentication is required in either case, you need to specify the username a wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh && sh onboard_agent.sh -p [protocol://]<proxy user>:<proxy password>@<proxyhost>[:port] -w <YOUR WORKSPACE ID> -s <YOUR WORKSPACE PRIMARY KEY> ``` -1. To configure the Linux computer to connect to Log Analytics workspace in Azure Government cloud, run the following command providing the workspace ID and primary key copied earlier. The following command downloads the agent, validates its checksum, and installs it. +1. To configure the Linux computer to connect to a Log Analytics workspace in Azure Government cloud, run the following command that provides the workspace ID and primary key copied earlier. The following command downloads the agent, validates its checksum, and installs it. ``` wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh && sh onboard_agent.sh -w <YOUR WORKSPACE ID> -s <YOUR WORKSPACE PRIMARY KEY> -d opinsights.azure.us If authentication is required in either case, you need to specify the username a ``` wget https://raw.githubusercontent.com/Microsoft/OMS-Agent-for-Linux/master/installer/scripts/onboard_agent.sh && sh onboard_agent.sh -p [protocol://]<proxy user>:<proxy password>@<proxyhost>[:port] -w <YOUR WORKSPACE ID> -s <YOUR WORKSPACE PRIMARY KEY> -d opinsights.azure.us ```-1. Restart the agent by running the following command: +1. Restart the agent by running the following command: ``` sudo /opt/microsoft/omsagent/bin/service_control restart [<workspace id>] If authentication is required in either case, you need to specify the username a ### [Shell](#tab/shell) -The Log Analytics agent for Linux is provided in a self-extracting and installable shell script bundle. This bundle contains Debian and RPM packages for each of the agent components and can be installed directly or extracted to retrieve the individual packages. One bundle is provided for x64 and one for x86 architectures. +The Log Analytics agent for Linux is provided in a self-extracting and installable shell script bundle. This bundle contains Debian and RPM packages for each of the agent components and can be installed directly or extracted to retrieve the individual packages. One bundle is provided for x64 and one for x86 architectures. > [!NOTE]-> For Azure VMs, we recommend you install the agent on them using the [Azure Log Analytics VM extension](../../virtual-machines/extensions/oms-linux.md) for Linux. +> For Azure VMs, we recommend that you install the agent on them by using the [Azure Log Analytics VM extension](../../virtual-machines/extensions/oms-linux.md) for Linux. --1. [Download](https://github.com/microsoft/OMS-Agent-for-Linux#azure-install-guide) and transfer the appropriate bundle (x64 or x86) to your Linux VM or physical computer, using scp/sftp. +1. [Download](https://github.com/microsoft/OMS-Agent-for-Linux#azure-install-guide) and transfer the appropriate bundle (x64 or x86) to your Linux VM or physical computer by using scp/sftp. 1. Install the bundle by using the `--install` argument. To onboard to a Log Analytics workspace during installation, provide the `-w <WorkspaceID>` and `-s <workspaceKey>` parameters copied earlier. >[!NOTE]- > Use the `--upgrade` argument if any dependent packages such as omi, scx, omsconfig, or their older versions are installed, as would be the case if the system Center Operations Manager agent for Linux is already installed. + > Use the `--upgrade` argument if any dependent packages, such as omi, scx, omsconfig, or their older versions, are installed. This would be the case if the System Center Operations Manager agent for Linux is already installed. ``` sudo sh ./omsagent-*.universal.x64.sh --install -w <workspace id> -s <shared key> --skip-docker-provider-install ``` > [!NOTE]- > The command above uses the optional `--skip-docker-provider-install` flag to disable the Container Monitoring data collection because the [Container Monitoring solution](../containers/containers.md) is being retired. + > The preceding command uses the optional `--skip-docker-provider-install` flag to disable the Container Monitoring data collection because the [Container Monitoring solution](../containers/containers.md) is being retired. -1. To configure the Linux agent to install and connect to a Log Analytics workspace through a Log Analytics gateway, run the following command providing the proxy, workspace ID, and workspace key parameters. This configuration can be specified on the command line by including `-p [protocol://][user:password@]proxyhost[:port]`. The *proxyhost* property accepts a fully qualified domain name or IP address of the Log Analytics gateway server. +1. To configure the Linux agent to install and connect to a Log Analytics workspace through a Log Analytics gateway, run the following command. It provides the proxy, workspace ID, and workspace key parameters. This configuration can be specified on the command line by including `-p [protocol://][user:password@]proxyhost[:port]`. The `proxyhost` property accepts a fully qualified domain name or IP address of the Log Analytics gateway server. ``` sudo sh ./omsagent-*.universal.x64.sh --upgrade -p https://<proxy address>:<proxy port> -w <workspace id> -s <shared key> ``` - If authentication is required, you need to specify the username and password. For example: + If authentication is required, specify the username and password. For example: ``` sudo sh ./omsagent-*.universal.x64.sh --upgrade -p https://<proxy user>:<proxy password>@<proxy address>:<proxy port> -w <workspace id> -s <shared key> ``` -1. To configure the Linux computer to connect to a Log Analytics workspace in Azure Government cloud, run the following command providing the workspace ID and primary key copied earlier. +1. To configure the Linux computer to connect to a Log Analytics workspace in Azure Government cloud, run the following command that provides the workspace ID and primary key copied earlier: ``` sudo sh ./omsagent-*.universal.x64.sh --upgrade -w <workspace id> -s <shared key> -d opinsights.azure.us sudo sh ./omsagent-*.universal.x64.sh --extract Upgrading from a previous version, starting with version 1.0.0-47, is supported in each release. Perform the installation with the `--upgrade` parameter to upgrade all components of the agent to the latest version. > [!NOTE]-> There will be a warning message during the upgrade "docker provider package installation skipped" since --skip-docker-provider-install flag is set. If you are installing over an existing omsagent install and wish to remove the docker provider, you should first purge the existing installation and then install using the --skip-docker-provider-install flag. -+> The warning message "docker provider package installation skipped" appears during the upgrade because the `--skip-docker-provider-install` flag is set. If you're installing over an existing `omsagent` installation and want to remove the docker provider, purge the existing installation first. Then install by using the `--skip-docker-provider-install` flag. ## Cache information-Data from the Log Analytics agent for Linux is cached on the local machine at *%STATE_DIR_WS%/out_oms_common*.buffer* before it's sent to Azure Monitor. Custom log data is buffered in *%STATE_DIR_WS%/out_oms_blob*.buffer*. The path may be different for some [solutions and data types](https://github.com/microsoft/OMS-Agent-for-Linux/search?utf8=%E2%9C%93&q=+buffer_path&type=). +Data from the Log Analytics agent for Linux is cached on the local machine at *%STATE_DIR_WS%/out_oms_common*.buffer* before it's sent to Azure Monitor. Custom log data is buffered in *%STATE_DIR_WS%/out_oms_blob*.buffer*. The path might be different for some [solutions and data types](https://github.com/microsoft/OMS-Agent-for-Linux/search?utf8=%E2%9C%93&q=+buffer_path&type=). -The agent attempts to upload every 20 seconds. If it fails, it waits an exponentially increasing length of time until it succeeds: 30 seconds before the second attempt, 60 seconds before the third, 120 seconds, and so on, up to a maximum of 16 minutes between retries until it successfully connects again. The agent retries up to 6 times for a given chunk of data before discarding and moving to the next one. This continues until the agent can successfully upload again. This means that data may be buffered up to approximately 30 minutes before being discarded. +The agent attempts to upload every 20 seconds. If it fails, it waits an exponentially increasing length of time until it succeeds. For example, it waits 30 seconds before the second attempt, 60 seconds before the third, 120 seconds, and so on, up to a maximum of 16 minutes between retries until it successfully connects again. The agent retries up to six times for a given chunk of data before discarding and moving to the next one. This process continues until the agent can successfully upload again. For this reason, the data might be buffered up to approximately 30 minutes before it's discarded. The default cache size is 10 MB but can be modified in the [omsagent.conf file](https://github.com/microsoft/OMS-Agent-for-Linux/blob/e2239a0714ae5ab5feddcc48aa7a4c4f971417d4/installer/conf/omsagent.conf). - ## Next steps - Review [Managing and maintaining the Log Analytics agent for Windows and Linux](agent-manage.md) to learn about how to reconfigure, upgrade, or remove the agent from the virtual machine.--- Review [Troubleshooting the Linux agent](agent-linux-troubleshoot.md) if you encounter issues while installing or managing the agent.--- Review [Agent Data Sources](./agent-data-sources.md) to learn about data source configuration.+- Review [Troubleshooting the Linux agent](agent-linux-troubleshoot.md) if you encounter issues while you're installing or managing the agent. +- Review [Agent data sources](./agent-data-sources.md) to learn about data source configuration. |
azure-monitor | Agent Windows Troubleshoot | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-monitor/agents/agent-windows-troubleshoot.md | If the query returns results, you need to determine if a particular data type is |Event ID |Source |Description |Resolution | ||-||--| |8000 |HealthService |This event will specify if a workflow related to performance, event, or other data type collected is unable to forward to the service for ingestion to the workspace. | Event ID 2136 from source HealthService is written together with this event and can indicate the agent is unable to communicate with the service. Possible reasons might be misconfiguration of the proxy and authentication settings, network outage, or the network firewall or proxy doesn't allow TCP traffic from the computer to the service.|- |10102 and 10103 |Health Service Modules |Workflow couldn't resolve the data source. |This issue can occur if the specified performance counter or instance doesn't exist on the computer or is incorrectly defined in the workspace data settings. If this is a user-specified [performance counter](data-sources-performance-counters.md#configuring-performance-counters), verify the information specified follows the correct format and exists on the target computers. | + |10102 and 10103 |Health Service Modules |Workflow couldn't resolve the data source. |This issue can occur if the specified performance counter or instance doesn't exist on the computer or is incorrectly defined in the workspace data settings. If this is a user-specified [performance counter](data-sources-performance-counters.md#configure-performance-counters), verify the information specified follows the correct format and exists on the target computers. | |26002 |Health Service Modules |Workflow couldn't resolve the data source. |This issue can occur if the specified Windows event log doesn't exist on the computer. This error can be safely ignored if the computer isn't expected to have this event log registered. Otherwise, if this is a user-specified [event log](data-sources-windows-events.md#configure-windows-event-logs), verify the information specified is correct. | |
azure-monitor | Data Sources Iis Logs | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-monitor/agents/data-sources-iis-logs.md | Title: Collect IIS logs with Log Analytics agent in Azure Monitor -description: Internet Information Services (IIS) stores user activity in log files that can be collected by Azure Monitor. This article describes how to configure collection of IIS logs and details of the records they create in Azure Monitor. + Title: Collect IIS logs with the Log Analytics agent in Azure Monitor +description: This article describes how to configure collection of IIS log files that store user activity and the details of the records they create in Azure Monitor. Last updated 03/31/2022 -# Collect IIS logs with Log Analytics agent in Azure Monitor +# Collect IIS logs with the Log Analytics agent in Azure Monitor Internet Information Services (IIS) stores user activity in log files that can be collected by the Log Analytics agent and stored in [Azure Monitor Logs](../data-platform.md). - + > [!IMPORTANT]-> This article covers collecting IIS logs with the [Log Analytics agent](./log-analytics-agent.md), which **will be deprecated by August 2024**. Please be sure to [migrate to Azure Monitor agent](./azure-monitor-agent-manage.md) before August 2024 to continue ingesting data. See [Collect text logs with Azure Monitor agent (preview)](../agents/data-collection-text-log.md) for details on collecting IIS logs with [Azure Monitor agent](azure-monitor-agent-overview.md). +> This article covers collecting IIS logs with the [Log Analytics agent](./log-analytics-agent.md), which **will be deprecated by August 2024**. Be sure to [migrate to Azure Monitor Agent](./azure-monitor-agent-manage.md) before August 2024 to continue ingesting data. See [Collect text logs with Azure Monitor Agent (preview)](../agents/data-collection-text-log.md) for details on collecting IIS logs with [Azure Monitor Agent](azure-monitor-agent-overview.md). --## Configuring IIS logs +## Configure IIS logs Azure Monitor collects entries from log files created by IIS, so you must [configure IIS for logging](/previous-versions/orphan-topics/ws.11/hh831775(v=ws.11)). -Azure Monitor only supports IIS log files stored in W3C format and does not support custom fields or IIS Advanced Logging. It does not collect logs in NCSA or IIS native format. --Configure IIS logs in Azure Monitor from the [Agent configuration menu](../agents/agent-data-sources.md#configure-data-sources) for the Log Analytics agent. There is no configuration required other than selecting **Collect W3C format IIS log files**. +Azure Monitor only supports IIS log files stored in W3C format and doesn't support custom fields or IIS Advanced Logging. It doesn't collect logs in NCSA or IIS native format. +Configure IIS logs in Azure Monitor from the [Agent configuration menu](../agents/agent-data-sources.md#configure-data-sources) for the Log Analytics agent. No configuration is required other than selecting **Collect W3C format IIS log files**. ## Data collection-Azure Monitor collects IIS log entries from each agent each time the log timestamp changes. The log is read every **5 minutes**. If for any reason IIS doesn't update the timestamp before the rollover time when a new file is created, entries will be collected following creation of the new file. The frequency of new file creation is controlled by the **Log File Rollover Schedule** setting for the IIS site, which is once a day by default. If the setting is **Hourly**, Azure Monitor collects the log each hour. If the setting is **Daily**, Azure Monitor collects the log every 24 hours. +Azure Monitor collects IIS log entries from each agent each time the log timestamp changes. The log is read every 5 minutes. If for any reason IIS doesn't update the timestamp before the rollover time when a new file is created, entries will be collected following creation of the new file. ++The frequency of new file creation is controlled by the **Log File Rollover Schedule** setting for the IIS site. The setting is once a day by default. If the setting is **Hourly**, Azure Monitor collects the log each hour. If the setting is **Daily**, Azure Monitor collects the log every 24 hours. > [!IMPORTANT]-> It is recommended to set the **Log File Rollover Schedule** to **Hourly**. If it's set to **Daily**, you may experience spikes in your data since it will only be collected once per day. +> We recommend that you set **Log File Rollover Schedule** to **Hourly**. If it's set to **Daily**, you might experience spikes in your data because it will be collected only once per day. ## IIS log record properties-IIS log records have a type of **W3CIISLog** and have the properties in the following table: +IIS log records have a type of **W3CIISLog** and have the properties shown in the following table: | Property | Description | |: |: | | Computer |Name of the computer that the event was collected from. | | cIP |IP address of the client. |-| csMethod |Method of the request such as GET or POST. | +| csMethod |Method of the request, such as GET or POST. | | csReferer |Site that the user followed a link from to the current site. | | csUserAgent |Browser type of the client. | | csUserName |Name of the authenticated user that accessed the server. Anonymous users are indicated by a hyphen. |-| csUriStem |Target of the request such as a web page. | +| csUriStem |Target of the request, such as a webpage. | | csUriQuery |Query, if any, that the client was trying to perform. |-| ManagementGroupName |Name of the management group for Operations Manager agents. For other agents, this is AOI-\<workspace ID\> | +| ManagementGroupName |Name of the management group for Operations Manager agents. For other agents, this name is AOI-\<workspace ID\>. | | RemoteIPCountry |Country/region of the IP address of the client. | | RemoteIPLatitude |Latitude of the client IP address. | | RemoteIPLongitude |Longitude of the client IP address. | IIS log records have a type of **W3CIISLog** and have the properties in the foll | scSubStatus |Substatus error code. | | scWin32Status |Windows status code. | | sIP |IP address of the web server. |-| SourceSystem |OpsMgr | +| SourceSystem |OpsMgr. | | sPort |Port on the server the client connected to. | | sSiteName |Name of the IIS site. | | TimeGenerated |Date and time the entry was logged. | IIS log records have a type of **W3CIISLog** and have the properties in the foll | csBytes | Number of bytes that the server received. | ## Log queries with IIS logs-The following table provides different examples of log queries that retrieve IIS log records. +Different examples of log queries that retrieve IIS log records are shown in the following table: | Query | Description | |: |: | |
azure-monitor | Data Sources Performance Counters | https://github.com/MicrosoftDocs/azure-docs/commits/main/articles/azure-monitor/agents/data-sources-performance-counters.md | Title: Collect Windows and Linux performance data sources with Log Analytics agent in Azure Monitor -description: Performance counters are collected by Azure Monitor to analyze performance on Windows and Linux agents. This article describes how to configure collection of Performance counters for both Windows and Linux agents, details of they are stored in the workspace, and how to analyze them in the Azure portal. + Title: Collect Windows and Linux performance data sources with the Log Analytics agent in Azure Monitor +description: Learn how to configure collection of performance counters for Windows and Linux agents, how they're stored in the workspace, and how to analyze them. Last updated 06/28/2022 -# Collect Windows and Linux performance data sources with Log Analytics agent -Performance counters in Windows and Linux provide insight into the performance of hardware components, operating systems, and applications. Azure Monitor can collect performance counters from Log Analytics agents at frequent intervals for Near Real Time (NRT) analysis in addition to aggregating performance data for longer term analysis and reporting. +# Collect Windows and Linux performance data sources |