From 9b9a9d12d781c5400164b74cd97a943e72af6fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Rodr=C3=ADguez?= Date: Thu, 24 Jun 2021 17:21:01 -0400 Subject: [PATCH] [Identity] Samples aligned with other languages (v1 compatible) (#15031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this PR we're aligning the samples of Identity with other languages. The samples I'm adding in this PR are: - Rolling certificates with ClientCertificateCredential ([.Net](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/samples/ClientCertificateCredentialSamples.md#rolling-certificates)). - ClientCertificateCredential with a Key Vault Certificate ([Python](https://github.com/Azure/azure-sdk-for-python/pull/18109)) (decided not to use `@azure/keyvault-certificates` because of the possible issues converting certificates from one format to another in Node). - Custom credentials ([.Net](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/samples/DefiningCustomCredentialTypes.md#defining-custom-credential-types)). - Using MSAL directly ([.Net](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/samples/DefiningCustomCredentialTypes.md#authenticating-with-msal-directly)). - On Behalf Of Flow ([.Net](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/samples/DefiningCustomCredentialTypes.md#authenticating-with-the-on-behalf-of-flow)). New samples related to the v2-specific features will be added after the Identity package is separated. Related to #14435 --- I’ve decided to use this opportunity to: Fix #15324 This PR also implicitly: Fixes #15573 --- .../identity/samples/AzureIdentityExamples.md | 557 +++++++++++++++--- 1 file changed, 490 insertions(+), 67 deletions(-) diff --git a/sdk/identity/identity/samples/AzureIdentityExamples.md b/sdk/identity/identity/samples/AzureIdentityExamples.md index af07eabf52d8..9fde9177df7f 100644 --- a/sdk/identity/identity/samples/AzureIdentityExamples.md +++ b/sdk/identity/identity/samples/AzureIdentityExamples.md @@ -1,33 +1,48 @@ # Table of contents - [Introduction](#introduction) -- [Authenticating client side browser applications](#authenticating-client-side-browser-applications) -- [Authenticating server side applications](#authenticating-server-side-applications) +- [Requirements](#requirements) +- [Authenticating client-side browser applications](#authenticating-client-side-browser-applications) +- [Authenticating server-side applications](#authenticating-server-side-applications) - [Authenticating User Accounts](#authenticating-user-accounts) - [Authenticating User Accounts with developer tools](#authenticating-user-accounts-with-developer-tools) - [Authenticating Service Principals](#authenticating-service-principals) - [Authenticating Azure Hosted Applications](#authenticating-azure-hosted-applications) - [Chaining credentials](#chaining-credentials) - [Authenticating With Azure Stack using Azure Identity](#authenticating-with-azure-stack-using-azure-identity) +- [Authenticating With Azure Stack using Azure Identity](#authenticating-with-azure-stack-using-azure-identity) +- [Advanced Examples](#advanced-examples) + - [Custom Credentials](#custom-credentials) + - [Authenticating with a pre-fetched access token](#authenticating-with-a-pre-fetched-access-token). + - [Authenticating with MSAL directly](#authenticating-with-msal-directly). + - [Authenticating with the @azure/msal-node Confidential Client](#authenticating-with-the-azure-msal-node-confidential-client). + - [Authenticating with the @azure/msal-node On Behalf Flow](#authenticating-with-the-azure-msal-node-on-behalf-flow). + - [Authenticating with the @azure/msal-browser Public Client](#authenticating-with-the-azure-msal-browser-public-client). + - [Authenticating with Key Vault Certificates](#authenticating-with-key-vault-certificates) + - [Rolling Certificates](#rolling-certificates) ## Introduction -Authenticating your application, users, and principals is an integral part of working with the Azure Client Libraries. The Azure Identity library provides multiple ways to authenticate, each with a flexible configuration that covers most scenarios. In this document we will go over some of these scenarios and provide small examples that can be used as a starting point for your needs. +Authenticating your application, users, and principals is an integral part of working with the Azure client libraries. The Azure Identity library provides multiple ways to gain access to the Azure services, each with a flexible configuration that covers most scenarios. There is sample code in [JavaScript](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity/samples/javascript) and [TypeScript](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity/samples/typescript) to cover the basic authentication scenarios. This document covers several use cases of Identity with greater context and links to the underlying authentication flows and other available documentation. -## Authenticating client side browser applications +## Authenticating client-side browser applications -For client side applications running in the browser, the `InteractiveBrowserCredential` provides the simplest user authentication experience and is the only credential type that we support in the browser. To get started, you need to register your application in the Microsoft identity platform and set the right permissions. +For client-side applications running in the browser, the `InteractiveBrowserCredential` provides the most direct user authentication experience. It's the only credential type that we support in the browser. To get started, register your application in the Microsoft Identity platform and set the proper permissions. - [Register a single page application](https://docs.microsoft.com/azure/active-directory/develop/scenario-spa-app-registration) in the Microsoft identity platform - Configure the app registration with a redirect URI to specify where the Microsoft identity platform should redirect the client along with any security tokens. - If using v1 of `@azure/identity` package, follow the instructions at [Redirect URI: MSAL.js 1.0 with implicit flow](https://docs.microsoft.com/azure/active-directory/develop/scenario-spa-app-registration#redirect-uri-msaljs-10-with-implicit-flow) to set the redirect URI. - If using v2 of `@azure/identity` package, follow the instructions at [Redirect URI: MSAL.js 2.0 with auth code flow](https://docs.microsoft.com/azure/active-directory/develop/scenario-spa-app-registration#redirect-uri-msaljs-20-with-auth-code-flow) -- Ensure that your application has the right permission for the APIs it intends to use. +- Ensure that your application has the correct permission for the APIs it intends to use. - In your app registration in the Azure portal, go to `API Permissions` - Click on `Add a permission` - - Select the API you want to use. For example, if you are using any of our management/control plane packages i.e. the ones whose name starts with `@azure/arm-`, then you should select ``Azure Service Management`. + - Select the API you want to use. For example, if you're using any of our management/control plane packages (the ones whose name starts with `@azure/arm-`), you should select **Azure Service Management**. +- Ensure that your AAD Application has enabled public authentication flows: + - Go to Azure Active Directory in the Azure portal and find your app registration. + - Navigate to the **Authentication** section. + - Under **Advanced settings**, select **yes** on the option **Allow public client flows**. -Copy the client ID and tenant ID from the `Overview` section of your app registration in Azure portal and use it in the below code snippet where we authenticate a `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] using the `InteractiveBrowserCredential`. +Copy the client ID and tenant ID from the **Overview** section of your app registration in the Azure portal and use it in the below code snippet where we authenticate a `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] using the `InteractiveBrowserCredential`. ```ts function withInteractiveBrowserCredential() { @@ -40,22 +55,23 @@ function withInteractiveBrowserCredential() { } ``` -## Authenticating server side applications +If your project is already using MSAL to authenticate on the browser, or if you're looking for more advanced authentication scenarios in the browser, the Azure SDK makes it easy to use MSAL directly to authenticate our clients: [Authenticating with the @azure/msal-browser Public Client](#authenticating-with-the-azure-msal-browser-public-client). + +## Authenticating server-side applications -For server side applications we provide options that vary from minimal configuration with sensible defaults using the `DefaultAzureCredential` to more specialized credentials that can support your specific scenario. +For server-side applications, we provide options that vary from a minimal configuration with sensible defaults using the `DefaultAzureCredential` to more specialized credentials. -- To get started, you can always rely on interactive authentication of your user account which requires minimum setup. -- As you develop your application, you may want to first sign in using the developer tools like Azure CLI or Azure PowerShell to avoid signing in interactively every time you run your application. -- As you deploy your application to Azure App Service or run it in a virtual machine, you may want to make use of [Managed Identity](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview). +- To get started, you can always rely on interactive authentication of your user account, which requires minimal setup. +- As you develop your application, you may want to sign in using the developer tools like Azure CLI or Azure PowerShell, to avoid signing in interactively every time you run your application. +- As you deploy your application to Azure App Service or run it in a virtual machine, you may want to use [Managed Identity](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview). -You can [chain multiple credentials](#chaining-credentials) together so that they are tried sequentially until one of them succeeds. -This is useful to make use of different authentication mechanisms based on your environment without changing your application code. +We also provide a way to chain multiple credentials so that they try to authenticate sequentially until one of them succeeds. Chaining credentials will allow your code to work in multiple environments, including your local development tools. For more information, go to the section: [Chaining credentials](#chaining-credentials). One such chained credential that we provide out of the box is `DefaultAzureCredential`. ### Authenticating User Accounts -Authenticating user accounts is the easiest way to get started with minimal set up. For production scenarios, we recommend authenticating using service principals or managed identity which are listed in the later sections. +Authenticating user accounts is the easiest way to get started with minimal set up. For production scenarios, we recommend authenticating using service principals or managed identities, which are listed in the later sections. | Credential with example | Usage | Setup required | | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | @@ -74,7 +90,7 @@ Authenticating user accounts is the easiest way to get started with minimal set ### Authenticating Service Principals -An Azure service principal is an identity created for use with applications, hosted services, and automated tools to access Azure resources. This access 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. +An Azure service principal is an identity created for use with applications, hosted services, and automated tools to access Azure resources. The roles assigned by the service principal will determine what resources are accessible. For security reasons, use service principals through automation rather than allowing them to log in with a user identity. To learn more, read [Application and service principal objects in Azure Active Directory][app-register-service-principal] @@ -88,7 +104,7 @@ To learn more, read [Application and service principal objects in Azure Active D | [ClientSecretCredential](#authenticating-a-service-principal-with-a-client-secret) | Authenticates a service principal using a secret. | | [ClientCertificateCredential](#authenticating-a-service-principal-with-a-client-certificate) | Authenticates a service principal using a certificate. | | [EnvironmentCredential](#authenticating-a-service-principal-with-environment-credentials) | Authenticates a service principal or user via credential information specified in environment variables. | -| [DefaultAzureCredential](#authenticating-with-defaultazurecredential) | Tries `EnvironmentCredential`, `AzureCliCredential`, `AzurePowerShellCredential` and other credentials sequentially until one of them succeeds. Use this to have your application authenticate using developer tools, service principals or managed identity based on what is available in the current environment without changing your code. | +| [DefaultAzureCredential](#authenticating-with-defaultazurecredential) | Tries `EnvironmentCredential`, `AzureCliCredential`, `AzurePowerShellCredential`, and other credentials sequentially until one of them succeeds. Use this to have your application authenticate using developer tools, service principals, or managed identity based on what's available in the current environment without changing your code. | ### Authenticating Azure Hosted Applications @@ -96,7 +112,7 @@ If your application is hosted in Azure, you can make use of [Managed Identity](h | Credential with example | Usage | | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [ManagedIdentityCredential](#authenticating-in-azure-with-managed-identity) | Authenticate in a virtual machine, app service, function app, cloud shell, or AKS environment on Azure, with system assigned managed identity, user assigned managed identity, or app registration (when working with AKS pod-identity). | +| [ManagedIdentityCredential](#authenticating-in-azure-with-managed-identity) | Authenticate in a virtual machine, App Service, Functions app, Cloud Shell, or AKS environment on Azure, with system-assigned managed identity, user-assigned managed identity, or app registration (when working with AKS pod identity). | | [DefaultAzureCredential](#authenticating-with-defaultazurecredential) | Tries `EnvironmentCredential`, `ManagedIdentityCredential`, `AzureCliCredential`, `AzurePowerShellCredential`, and other credentials sequentially until one of them succeeds. Use this to have your application authenticate using developer tools, service principals or managed identity based on what is available in the current environment without changing your code. | ### Examples @@ -108,7 +124,7 @@ This example demonstrates authenticating the `SecretClient` from the [@azure/key ```ts /** * The default credential first checks environment variables for configuration. - * If environment configuration is incomplete, it will try managed identity. + * If the environment configuration is incomplete, it will try managed identity. */ function withDefaultAzureCredential() { const credential = new DefaultAzureCredential(); @@ -116,15 +132,15 @@ function withDefaultAzureCredential() { } ``` -#### Authenticating a user assigned managed identity with `DefaultAzureCredential` +#### Authenticating a user-assigned managed identity with `DefaultAzureCredential` -This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `DefaultAzureCredential`, deployed to an Azure resource with a user assigned managed identity configured. +This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `DefaultAzureCredential`, deployed to an Azure resource with a user-assigned managed identity configured. -For more information about how to configure a user assigned managed identity for an Azure resource please refer to [What are managed identities for Azure resources][azure_managed_identities]. +For more information about configuring a user-assigned managed identity for an Azure resource, refer to [What are managed identities for Azure resources][azure_managed_identities]. ```ts /** - * The default credential will use the user assigned managed identity with the specified client ID. + * The default credential will use the user-assigned managed identity with the specified client ID. */ function withDefaultAzureCredential() { // Alternatively, you may set the environment variable AZURE_CLIENT_ID="" and omit the `managedIdentityClientId` @@ -138,9 +154,11 @@ function withDefaultAzureCredential() { #### Authenticating a user account interactively in the browser -For clients that have a default browser available and for client-side applications running in the browser, the `InteractiveBrowserCredential` provides the simplest user authentication experience. In the sample below an application authenticates a `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] using the `InteractiveBrowserCredential`. +For clients with a default browser available and client-side applications running in the browser, the `InteractiveBrowserCredential` provides the most direct user authentication experience. In the sample below, an application authenticates a `SecretClient` from the [@azure/service-bus][service_bus_client_library] using the `InteractiveBrowserCredential`. + +For Node.js, if a `clientId` is provided, the Azure Active Directory application will need to be configured to have a "Mobile and desktop applications" redirect endpoint. Follow our guide on [setting up Redirect URIs for Desktop apps that calls to web APIs](https://docs.microsoft.com/azure/active-directory/develop/scenario-desktop-app-registration#redirect-uris). -> For client side applications running in the browser, the `InteractiveBrowserCredential` is the only credential type that is supported. You will also need to configure your app registration for single-page applications and set the right permissions. Please refer to the [Authenticating client side browser applications](#authenticating-client-side-browser-applications) for more information. +For client-side applications running in the browser, the `InteractiveBrowserCredential` is the only credential type that is supported. For more information, see [Authenticating client-side browser applications](#authenticating-client-side-browser-applications). ```ts function withInteractiveBrowserCredential() { @@ -148,8 +166,7 @@ function withInteractiveBrowserCredential() { tenantId: "", clientId: "" }); - - const client = new SecretClient("https://key-vault-name.vault.azure.net", credential); + const client = new ServiceBusClient("", credential); } ``` @@ -157,14 +174,14 @@ function withInteractiveBrowserCredential() { This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `ClientSecretCredential`. There's also [a runnable sample](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/identity/identity/samples/typescript/src/clientSecretCredential.ts) to create a Key Vault key client you can copy-paste. -An Azure service principal is an identity created for use with applications, hosted services, and automated tools to access Azure resources. This access 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. +You'll need to: -To learn more, read [Application and service principal objects in Azure Active Directory][app-register-service-principal] +- [Create an application registration][quickstart-register-app] +- [Create a Service Principal with the Azure CLI][service_principal_azure_cli] or [Create an Azure service principal with Azure PowerShell][service_principal_azure_powershell] -Set up: +To learn more about service principals, see [Application and service principal objects in Azure Active Directory][app-register-service-principal]. -- [Application registration][quickstart-register-app] -- [Create a Service Principal with the Azure CLI][service_principal_azure_cli] or [Create an Azure service principal with Azure PowerShell][service_principal_azure_powershell] +In the following sample, an application authenticates a `SecretClient` from the [@azure/service-bus][service_bus_client_library] using the `ClientSecretCredential`: ```ts /** @@ -176,26 +193,31 @@ function withClientSecretCredential() { "", "" ); - const client = new SecretClient("https://key-vault-name.vault.azure.net", credential); + const client = new ServiceBusClient("", credential); } ``` #### Authenticating a service principal with environment credentials -This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `EnvironmentCredential`. The `EnvironmentCredential` looks for well-known environment variable names to determine how it should authenticate. It effectively acts as a wrapper for the `ClientSecretCredential`, `ClientCertificateCredential` or `UsernamePasswordCredential` depending on which environment variables are present. - -An Azure service principal is an identity created for use with applications, hosted services, and automated tools to access Azure resources. This access 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. +This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `EnvironmentCredential`. The `EnvironmentCredential`: -To learn more, read [Application and service principal objects in Azure Active Directory][app-register-service-principal] +- Looks for well-known environment variable names to determine how it should authenticate. +- Acts as a wrapper for the `ClientSecretCredential`, `ClientCertificateCredential`, or `UsernamePasswordCredential`, depending on which environment variables are present. -Set up: +You'll need to: -- [Application registration][quickstart-register-app] +- [Create an application registration][quickstart-register-app] - [Create a Service Principal with the Azure CLI][service_principal_azure_cli] or [Create an Azure service principal with Azure PowerShell][service_principal_azure_powershell] +- Provide the environment variables: + - `AZURE_TENANT_ID`, containing the AD tenant ID or name. + - `AZURE_CLIENT_ID`, containing the ID of the user/service principal to authenticate as. + - `AZURE_CLIENT_SECRET`, containing a client secret created belonging to the same user/service principal. + +To learn more about service principals, see [Application and service principal objects in Azure Active Directory][app-register-service-principal]. ```ts /** - * Authenticate with a client certificate. + * Authenticate using the AZURE_TENANT_ID, AZURE_CLIENT_ID, and AZURE_CLIENT_SECRET environment variables. */ function withEnvironmentCredential() { let credential = new EnvironmentCredential(); @@ -207,15 +229,13 @@ function withEnvironmentCredential() { This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `ClientCertificateCredential`. -An Azure service principal is an identity created for use with applications, hosted services, and automated tools to access Azure resources. This access 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. - -To learn more, read [Application and service principal objects in Azure Active Directory][app-register-service-principal] - -Set up: +You'll need to: -- [Application registration][quickstart-register-app] +- [Create an application registration][quickstart-register-app] - [Create a Service Principal with the Azure CLI][service_principal_azure_cli] or [Create an Azure service principal with Azure PowerShell][service_principal_azure_powershell] +To learn more about service principals, see [Application and service principal objects in Azure Active Directory][app-register-service-principal]. + ```ts /** * Authenticate with a client certificate. @@ -232,11 +252,21 @@ function withClientCertificateCredential() { #### Authenticating a user account with device code flow -This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `DeviceCodeCredential`. +This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `DeviceCodeCredential`. The `DeviceCodeCredential` offers a credential that can be used with little to no setup. The user can use the browser of their choice to complete the authentication process. + +To authenticate a user through device code flow, complete the following steps: + +1. Go to Azure Active Directory in Azure portal and find your app registration. +2. Navigate to the **Authentication** section. +3. Under **Advanced settings**, select `yes` on the option `Allow public client flows`. + +You also need to be the administrator of your tenant to grant consent to your application when you log in for the first time. -For more information about how to configure an AAD application for device code flow please refer to [Enable applications for device code flow][device_code_flow]. +If you can't configure the device code flow option on your Active Directory, it may require your app to be multi-tenant. To make your app multi-tenant: -> The `DeviceCodeCredential` offers a credential that can be used with little to no setup - the user is free to use whatever browser they choose to complete the authentication process. +1. Navigate to the **Authentication** panel. +2. Select **Accounts in any organizational directory**. +3. Select **yes** for **Treat application as Public Client**. ```ts /** @@ -259,7 +289,7 @@ function withDeviceCodeCredential() { This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `UsernamePasswordCredential`. The user must **not** have Multi-factor auth turned on. -Apart from user name and password, this credential requires you to know the tenant ID and client ID. To get the client ID, first [register your application][quickstart-register-app] +Apart from user name and password, this credential requires you to know the tenant ID and client ID. To get the client ID, first [register your application][quickstart-register-app]. ```ts /** @@ -278,15 +308,15 @@ function withClientCertificateCredential() { #### Authenticating a user account with auth code flow -This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `AuthorizationCodeCredential` on a web application. This can be useful when you want complete control over the authentication flow or when the `InteractiveBrowserCredential` does not fit your use-case. +This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `AuthorizationCodeCredential` on a Node.js service intended as the back-end for a web application. This can be useful when you want complete control over the authentication flow or when the `InteractiveBrowserCredential` doesn't fit your use case. -First, [register your application][quickstart-register-app] and get your client id, tenant id and redirect URL. +First, [register your application][quickstart-register-app] and get your client ID, tenant ID and redirect URL. -Next, prompt the user to login at the URL documented at [Microsoft identity platform and OAuth 2.0 authorization code flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code). You will need the client id, tenant id, redirect URL, and the scopes your application plans to access. +Next, prompt the user to login at the URL documented at [Microsoft identity platform and OAuth 2.0 authorization code flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code). You'll need the client ID, tenant ID, redirect URL, and the scopes your application plans to access. Then create an API at the redirect URL with the following code to access the Key Vault service. -For a complete example using the authorization code flow in Electron please refer to [our electron sample](https://github.com/Azure/azure-sdk-for-js/blob/main/samples/frameworks/electron/ts/src/authProvider.ts) +For a complete example using the authorization code flow in Electron, please refer to [our electron sample](https://github.com/Azure/azure-sdk-for-js/blob/main/samples/frameworks/electron/ts/src/authProvider.ts) ```ts /** @@ -308,7 +338,7 @@ function withAuthCodeCredential() { This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `AzureCliCredential` on a workstation with Azure CLI installed and signed in. -#### Configure the Azure CLI +##### Configure the Azure CLI Sign in using the [Azure CLI][azure_cli] @@ -353,7 +383,7 @@ function withAzureCliCredential() { This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `AzurePowerShellCredential` on a workstation with Azure PowerShell installed and authenticated. -#### Configure Azure PowerShell +##### Configure Azure PowerShell Sign in using [Azure PowerShell][azure_powershell]: @@ -361,7 +391,7 @@ Sign in using [Azure PowerShell][azure_powershell]: PS> Connect-AzAccount ``` -If the account / service principal has access to multiple tenants (subscriptions), ensure that the `Get-AzContext` cmdlet returns the correct subscription: +If the account/service principal has access to multiple tenants (subscriptions), ensure that the `Get-AzContext` cmdlet returns the correct subscription: ```powershell PS> Get-AzContext @@ -395,7 +425,7 @@ UserId : /** * Authenticate with Azure PowerShell */ -function withAzureCliCredential() { +function withAzurePowerShellCredential() { // Like the Azure CLI Credential, the Azure PowerShell Credential does not accept any // options or parameters, and uses the current user session within the Az.Account PowerShell // module. @@ -407,13 +437,13 @@ function withAzureCliCredential() { #### Authenticating in Azure with managed identity -This examples demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] client library using the `ManagedIdentityCredential` in a virtual machine, app service, function app, cloud shell, or AKS environment on Azure, with system assigned, or user assigned managed identity enabled. +This example demonstrates authenticating the `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] using the `ManagedIdentityCredential` in a virtual machine, App Service, Functions app, Cloud Shell, or AKS environment on Azure, with system-assigned or user-assigned managed identity enabled. -For more information about how to configure your Azure resource for managed identity please refer to [Configure managed identities for Azure resources](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/qs-configure-cli-windows-vm). +For more information about configuring your Azure resource for managed identity, see [Configure managed identities for Azure resources](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/qs-configure-cli-windows-vm). ```ts /** - * Authenticate with a system assigned managed identity. + * Authenticate with a system-assigned managed identity. */ function withSystemAssignedManagedIdentityCredential() { const credential = new ManagedIdentityCredential(); @@ -422,7 +452,7 @@ function withSystemAssignedManagedIdentityCredential() { } /** - * Authenticate with a user assigned managed identity. + * Authenticate with a user-assigned managed identity. */ function withUserManagedIdentityCredential() { const credential = new ManagedIdentityCredential(""); @@ -433,7 +463,7 @@ function withUserManagedIdentityCredential() { ## Chaining credentials -The `ChainedTokenCredential` class provides the ability to link together multiple credential instances to be tried sequentially when authenticating. The following example demonstrates creating a credential which will attempt to authenticate a `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] using managed identity, and fall back to certificate authentication if a managed identity is unavailable in the current environment. +The `ChainedTokenCredential` class provides the ability to link together multiple credential instances to be tried sequentially when authenticating. The following example demonstrates creating a credential that will attempt to authenticate a `SecretClient` from the [@azure/keyvault-secrets][secrets_client_library] using managed identity and fall back to certificate authentication if a managed identity is unavailable in the current environment. ```ts function withChainedTokenCredential() { @@ -449,7 +479,7 @@ function withChainedTokenCredential() { ### Determine the Azure Authority Host for Azure Stack -In powershell run this command or have your Azure Stack Administrator run this command: +In PowerShell, run this command or have your Azure Stack administrator run this command: ```powershell Get-AzEnvironment -Name @@ -467,8 +497,7 @@ The ActiveDirectory Authority in the output will be your Azure Authority Host ### Determine the Tenant ID for Azure Stack -If the Identity provider of your Azure Stack is Azure Active Directory (Azure AD) then contact your Azure Stack Administrator to find out your tenant ID. -else, if the Identity provider of your Azure Stack is Active Directory Federation Services (AD FS) then your tenant id is `adfs`. +If the Identity provider of your Azure Stack is Azure Active Directory (Azure AD), contact your Azure Stack administrator to find your tenant ID. Otherwise, if the Identity provider of your Azure Stack is Active Directory Federation Services (ADFS), your tenant ID is `adfs`. ### Authentication example @@ -491,13 +520,407 @@ function main() { } ``` +## Advanced Examples + +### Custom Credentials + +The `@azure/identity` library covers a broad range of Azure Active Directory authentication scenarios. However, we understand there are cases in which the credentials provided might not meet the specific needs of your application. Some applications might avoid taking a dependency on the `@azure/identity` package. In such cases, you may want to write your custom credential. + +In this section, we'll examine some such scenarios. + +### Authenticating with a pre-fetched access token + +The [@azure/core-auth][core_auth] package exports a `TokenCredential` interface. The interface is used by the `@azure/identity` package to define a standard public API for all of the Identity credentials we offer. There are cases in which it's convenient to create custom credentials. For example, when a token is pre-fetched, a custom `TokenCredential` can return that token as an `AccessToken` to the Azure SDK clients. + +In this example, `StaticTokenCredential` implements the `TokenCredential` abstraction. It takes a pre-fetched access token in its constructor as an [AccessToken](https://docs.microsoft.com/javascript/api/@azure/core-auth/accesstoken) and returns that from its implementation of `getToken()`. + +**Prerequisites** + +Install the [@azure/core-auth][core_auth] package. + +```ts +import { TokenCredential, AccessToken } from "@azure/core-auth"; + +class StaticTokenCredential implements TokenCredential { + // AccessToken is an object with two properties: + // - A "token" property with a string value. + // - And an "expiresOnTimestamp" property with a numeric unix timestamp as its value. + constructor(private accessToken: AccessToken) {} + async getToken(): Promise { + return this.accessToken; + } +} +``` + +Once the application has defined this credential, it can authenticate Azure SDK clients with a pre-fetched `AccessToken`. The following example shows how an application already using some other mechanism for acquiring tokens (the hypothetical method `getTokenForScope()`) could use the `StaticTokenCredential` to authenticate a `SecretClient` from `@azure/keyvault-secrets`. + +```ts +import { SecretClient } from "@azure/keyvault-secrets"; + +// StaticTokenCredential would be defined before the main() function... + +async function main() { + const accessToken = getTokenForScope("https://vault.azure.net/.default"); + + // In this case, `accessToken` has to contain two properties: + // - A "token" property with a string value. + // - And an "expiresOnTimestamp" property with a numeric unix timestamp as its value. + + const credential = new StaticTokenCredential(accessToken); + + const client = new SecretClient("https://myvault.vault.azure.net/", credential); +} +``` + +When using this custom credential type, it's the caller's responsibility to ensure the token is valid and contains the correct claims needed to authenticate calls from the particular service client. In the preceding case, the token must have the scope `https://vault.azure.net/.default` to authorize calls to Azure Blob Storage. + +### Authenticating with MSAL Directly + +Some applications already use the [@azure/msal-node][msal_node_npm] or [@azure/msal-browser][msal_browser_npm] package to authenticate portions of their application. In these cases, the application might want to use the same to authenticate Azure SDK clients, to take advantage of the token caching the MSAL client application is doing, and preventing unnecessary authentication calls. + +#### Authenticating with the @azure/msal-node Confidential Client + +In this example, the [ConfidentialClientApplicationCredential](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/master/lib/msal-node/docs/initialize-confidential-client-application.md) is constructed with an instance of `ConfidentialClientApplication` it then implements `getToken()` using the `acquireTokenByClientCredential()` method to acquire a token. + +**Prerequisites** + +Install the [@azure/msal-node][msal_node_npm] and [@azure/core-auth][core_auth]. + +> For more information about MSAL for Node.js, see [the README of the `@azure/msal-node` package][msal_node_readme]. +> For more information about working with the Confidential Client of MSAL, see [Initialization of MSAL (Node.js)](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/master/lib/msal-node/docs/initialize-confidential-client-application.md). + +```ts +import { TokenCredential, AccessToken } from "@azure/core-auth"; +import * as msalNode from "@azure/msal-node"; + +class ConfidentialClientCredential implements TokenCredential { + constructor(private confidentialApp: msalNode.ConfidentialClientApplication) {} + async getToken(scopes: string | string[]): Promise { + const result = await this.confidentialApp.acquireTokenByClientCredential({ + scopes: Array.isArray(scopes) ? scopes : [scopes] + }); + return { + token: result.accessToken, + expiresOnTimestamp: result.expiresOn.getTime() + }; + } +} +``` + +Users could then use the `ConfidentialClientApplicationCredential` to authenticate a `SecretClient` from `@azure/keyvault-secrets` with an MSAL `ConfidentialClientApplication`: + +```ts +import { SecretClient } from "@azure/keyvault-secrets"; +import * as msalNode from "@azure/msal-node"; + +async function main() { + const confidentialClient = new msalNode.ConfidentialClientApplication({ + // MSAL Configuration + }); + + const client = new SecretClient( + "https://myvault.vault.azure.net/", + new ConfidentialClientCredential(confidentialClient) + ); +} +``` + +#### Authenticating with the @azure/msal-node On Behalf Of Flow + +Currently, the `@azure/identity` library doesn't provide a credential type for clients which need to authenticate via the [On Behalf of Flow](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/master/lib/msal-common/docs/request.md#on-behalf-of-flow). While we may add support for this feature in the future, users currently requiring this will have to implement their own `TokenCredential` class. + +In this example, the `OnBehalfOfCredential` accepts a client ID, client secret, and a user's access token. It then creates an instance of `ConfidentialClientApplication` from MSAL to obtain an OBO token that can authenticate client requests. + +**Prerequisites** + +Install the [@azure/msal-node][msal_node_npm] and [@azure/core-auth][core_auth]. + +> For more information about MSAL for Node.js, see [the README of the `@azure/msal-node` package][msal_node_readme]. +> For more information about working with the Confidential Client of MSAL, see [Initialization of MSAL (Node.js)](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/master/lib/msal-node/docs/initialize-confidential-client-application.md). +> For more information about working with the On Behalf Flow with MSAL, see [On Behalf of Flow](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/master/lib/msal-common/docs/request.md#on-behalf-of-flow). + +```ts +import { TokenCredential, AccessToken } from "@azure/core-auth"; +import * as msalNode from "@azure/msal-node"; + +class OnBehalfOfCredential implements TokenCredential { + private confidentialApp: msalNode.ConfidentialClientApplication; + + constructor ( + private clientId: string, + private clientSecret: string, + private userAccessToken: string + ) { + this.confidentialApp = new msalNode.ConfidentialClientApplication({ + auth: { + clientId, + clientSecret + } + }); + } + async getToken(scopes: string | string[]): Promise { + const result = await this.confidentialApp.acquireTokenOnBehalfOf({ + scopes: Array.isArray(scopes) ? scopes : [scopes], + oboAssertion: this.userAccessToken + }); + return { + token: result.accessToken, + expiresOnTimestamp: result.expiresOn.getTime() + }; + } +} +``` + +The following example shows an how the `OnBehalfOfCredential` could be used to authenticate a `SecretClient`: + +```ts +import { SecretClient } from "@azure/keyvault-secrets"; + +async function main() { + const oboCredential = new OnBehalfOfCredential(clientId, clientSecret, userAccessToken); + + const client = new SecretClient("https://myvault.vault.azure.net/", oboCredential); +} +``` + +#### Authenticating with the @azure/msal-browser Public Client + +While `@azure/identity` provides some browser support, for users that need the complete feature set offered by `@azure/msal-browser`, it's possible to implement a `TokenCredential` on top of MSAL's public API for the browsers. + +For this example, you'll define a `BrowserCredential` class with the following methods: + +- `getToken` — Will use the Silent Authentication flow, retrieving the account from memory to prevent unnecessary redirections. +- `prepare` — Will try either to check if the account has previously authenticated or to parse the redirection URI values if present. +- `hasAuthenticated` — Can be used to determine if the authentication has taken place. +- `loginRedirect` — If called, this method triggers the authentication via redirection. + +**Prerequisites** + +Install the [@azure/msal-browser][msal_browser_npm] and [@azure/core-auth][core_auth]. + +> For more information about MSAL for browsers, see [the README of the `@azure/msal-browser` package][msal_browser_readme]. + +```ts +import { TokenCredential, AccessToken } from "@azure/core-auth"; +import * as msalBrowser from "@azure/msal-browser"; + +class BrowserCredential implements TokenCredential { + private publicApp: msalBrowser.PublicClientApplication; + private hasAuthenticated: boolean = false; + + constructor(clientId, redirectUri) { + this.publicApp = new msalBrowser.PublicClientApplication({ + auth: { + clientId, + redirectUri + } + }); + } + + // Either confirm the account already exists in memory, or tries to parse the redirect URI values. + async prepare(): Promise { + try { + if (await this.publicApp.getActiveAccount()) { + this.hasAuthenticated = true; + return; + } + await this.publicApp.handleRedirectPromise(); + this.hasAuthenticated = true; + } catch(e) { + console.error("BrowserCredential prepare() failed", e); + } + } + + // Should be true if prepare() was successful. + isAuthenticated(): boolean { + return this.hasAuthenticated; + } + + // If called, triggers authentication via redirection. + async loginRedirect(scopes: string | string[]): Promise { + const loginRequest = { + scopes: Array.isArray(scopes) ? scopes : [scopes] + }; + await this.app.loginRedirect(loginRequest); + } + + // Tries to retrieve the token without triggering a redirection. + async getToken(scopes: string | string[]): Promise { + if (!this.hasAuthenticated) { + throw new Error("Authentication required"); + } + + const parameters: msalBrowser.SilentRequest = { + account: await this.publicApp.getActiveAccount(), + scopes + }; + + const result = await this.publicApp.acquireTokenSilent(parameters); + return { + token: result.accessToken, + expiresOnTimestamp: result.expiresOn.getTime() + }; + } +} +``` + +The following example shows how the `BrowserCredential` could be used to authenticate a `ServiceBusClient`. For this example to work, the redirect URI configured in the AAD application should point to the same page that runs this code originally. For example, `http://localhost:80`. + +```ts +import { ServiceBusClient } from "@azure/service-bus"; + +async function main() { + const browserCredential = new BrowserCredential(clientId, location.origin); + + await browserCredential.prepare(); + + if (!browserCredential.isAuthenticated()) { + await browserCredential.loginRedirect("https://servicebus.azure.net/.default"); + } + + const client = new ServiceBusClient(serviceBusEndpoint, browserCredential); +} +``` + +### Authenticating with Key Vault Certificates + +Azure Key Vault supports creating secure certificates that can be used to authenticate Azure SDK clients. + +There are different ways to create Key Vault certificates. For example, through the Azure CLI: [Quickstart: Set and retrieve a certificate from Azure Key Vault using Azure CLI](https://docs.microsoft.com/azure/key-vault/certificates/quick-create-cli). + +Once you have a certificate, you may export the certificate with the Azure CLI following the steps at [Export certificates from Azure Key Vault](https://docs.microsoft.com/azure/key-vault/certificates/how-to-export-certificate?tabs=azure-cli). + +You can also export your certificate through the Azure portal. Navigate to your Key Vault resource, go to a specific certificate, then download the certificate in PFX/PEM format. + +Once you have a Key Vault certificate downloaded, go to Azure Active Directory. Find the Enterprise app you want to authenticate with, go to **Certificates & secrets**, and upload the certificate. + +After that, you can authenticate by pointing the `@azure/identity`'s `ClientCertificateCredential` to the PEM certificate's path, as follows: + +```ts +const credential = new ClientCertificateCredential( + "", + "", + "" +); +``` + +### Rolling Certificates + +Long-running applications may need to roll certificates during process execution. At the moment, the `ClientCertificateCredential` doesn't support certificate rotation. The credential treats the certificate provided as immutable. Therefore, clients constructed with a `ClientCertificateCredential` using a particular certificate would fail to authenticate requests after that certificate rolls and the original is no longer valid. + +However, if an application wants to roll this certificate without creating new service clients, it can accomplish this by creating its own `TokenCredential` implementation, which wraps the `ClientCertificateCredential`. Implementing this custom `TokenCredential` would somewhat depend on how the application handles certificate rotation. + +#### Explicit rotation + +If the application gets notified of certificate rotations and can directly respond, it might choose to wrap the `ClientCertificateCredential` in a custom credential which provides a means for rotating the certificate. + +**Prerequisites** + +Install the [@azure/core-auth][core_auth] package. + +```ts +import { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; +import { ClientCertificateCredential } from "@azure/identity"; + +class RotatableCertificateCredential implements TokenCredential { + private readonly tenantId: string; + private readonly clientId: string; + private credential: ClientCertificateCredential; + + constructor(tenantId: string, clientId: string, PEMCertificatePath: string) { + this.tenantId = tenantId; + this.clientId = clientId; + this.credential = new ClientCertificateCredential(tenantId, clientId, PEMCertificatePath); + } + + async getToken(scopes: string | string[], options?: GetTokenOptions): Promise { + return this.credential.getToken(scopes, options); + } + + rotateCertificate(PEMCertificatePath: string) { + this.credential = new ClientCertificateCredential( + this.tenantId, + this.clientId, + PEMCertificatePath + ); + } +} +``` + +The preceding example shows a custom credential type `RotatableCertificateCredential`, which provides a `rotateCertificate`. The implementation internally relies on an instance of `ClientCertificateCredential`. `rotateCertificate` replaces this instance with a new one using the new certificate path. + +#### Implicit rotation + +Some applications might want to respond to certificate rotations that are external to the application. For instance, a separate process rotates the certificate by updating it on disk. Here the application creates a custom credential that checks for certificate updates when tokens are requested. + +```ts +import { TokenCredential, GetTokenOptions, AccessToken } from "@azure/core-auth"; +import { ClientCertificateCredential } from "@azure/identity"; +import * as fs from "fs"; + +class RotatingCertificateCredential implements TokenCredential { + private readonly tenantId: string; + private readonly clientId: string; + private readonly certificatePath: string; + private promise: Promise | null = null; + private credential: ClientCertificateCredential; + private lastModified: number = 0; + + constructor(tenantId: string, clientId: string, certificatePath: string) { + this.tenantId = tenantId; + this.clientId = clientId; + this.certificatePath = certificatePath; + + this.refreshCertificate(); + } + + async getToken(scopes: string | string[], options?: GetTokenOptions): Promise { + await this.refreshCertificate(); + + return this.credential.getToken(scopes, options); + } + + refreshCertificate(): Promise { + if (this.promise) { + return this.promise; + } + return new Promise((resolve, reject) => { + fs.stat(this.certificatePath, (err, stats) => { + if (err) { + reject(err); + } else { + if (this.lastModified < stats.mtime.getTime()) { + this.lastModified = stats.mtime.getTime(); + this.credential = new ClientCertificateCredential( + this.tenantId, + this.clientId, + this.certificatePath + ); + this.promise = null; + } + resolve(); + } + }); + }); + } +} +``` + +In this example, the custom credential type `RotatingCertificateCredential` again uses a `ClientCertificateCredential` instance to retrieve tokens. However, in this case, it will attempt to refresh the certificate before obtaining the token. The method `RefreshCertificate` will query to see if the certificate has changed. If so, it will replace `this.credential` with a new instance of the certificate credential using the same certificate path. + [azure_cli]: https://docs.microsoft.com/cli/azure [secrets_client_library]: https://www.npmjs.com/package/@azure/keyvault-secrets +[service_bus_client_library]: https://www.npmjs.com/package/@azure/service-bus [azure_managed_identities]: https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview [service_principal_azure_cli]: https://docs.microsoft.com/cli/azure/create-an-azure-service-principal-azure-cli [device_code_flow]: https://github.com/Azure/azure-sdk-for-java/wiki/Set-up-Your-Environment-for-Authentication#enable-applications-for-device-code-flow [quickstart-register-app]: https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app [app-register-service-principal]: https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals [service_principal_azure_powershell]: https://docs.microsoft.com/powershell/azure/create-azure-service-principal-azureps +[msal_node_readme]: https://github.com/sadasant/microsoft-authentication-library-for-js/tree/master/lib/msal-node +[msal_node_npm]: https://www.npmjs.com/package/@azure/msal-node +[msal_browser_readme]: https://github.com/sadasant/microsoft-authentication-library-for-js/tree/master/lib/msal-browser +[msal_browser_npm]: https://www.npmjs.com/package/@azure/msal-browser +[core_auth]: https://www.npmjs.com/package/@azure/core-auth