Announcing the Azure Identity 2.0 client library and plugin packages for JavaScript
For the last several months, the Azure SDK team has been building the next major iteration (version 2.0) of the Azure Identity client library for JavaScript (@azure/identity). Version 2.0 reached General Availability (GA) on October 15, 2021. As the cornerstone of our Azure Active Directory authentication/authorization workflow, this new major version of @azure/identity
includes several improvements to the developer experience. Included are changes that reduce friction for developers who need to use @azure/identity
without native machine-code (NMC) dependencies.
This article focuses on the new plugin API and packages. Our goals for this iteration of the Identity library required a breaking change and a new major version. We also made a handful of other improvements to enhance the developer experience of using @azure/identity
while largely maintaining API compatibility with the previous version. Some improvements include:
- A backend rework that uses the latest versions, features, and default settings of the Microsoft Authentication Library (MSAL).
InteractiveBrowserCredential
now uses the Authorization Code Flow with Proof Key for Code Exchange (PKCE) by default. This change follows modern best practices for OAuth2/OpenID Connect authentication, instead of the implicit grant flow used in previous iterations.- The credentials’ constructors and
getToken
implementations now evaluate certain error cases differently, and no longer producenull
, instead throwing errors in all error cases.
To migrate your app to version 2.0 of the Identity library, see the Migration guide.
Plugin packages
The previous iteration of the Identity library optionally depended on the keytar
package. The package allowed access to the Azure account credentials stored in Visual Studio (VS) Code’s Azure Account extension. To support the goals for the next iteration of Identity, a new persistent token caching feature was introduced. This feature:
- Enables caching of access tokens between process sessions in a secure store.
- Required a dependency on @azure/msal-node-extensions, which relies on NMC to communicate with the Windows Data Protection API.
Several customers reported issues resulting from our dependence on these NMC modules, even “peer” or “optional” dependence. For example, some customers were unable or reasonably unwilling to build or use the modules because of security concerns. Sometimes security constraints in their CI/CD environments were to blame. Also, the newest versions of keytar
provide prebuilt binaries for many of the most common runtime platforms; however, there are situations that cause the keytar
installation to reject these prebuilt binaries and attempt to build itself. The @azure/msal-node-extensions
package doesn’t provide prebuilt binaries at this time. A build is always required to use it. Building these packages requires a full C/C++ build toolchain, such as:
- VS C++ build tools on Windows
- XCode Command-Line tools on macOS
- GCC/Clang and development headers on Linux
These requirements and the confusion around them added friction to the development process. The result was an unsatisfactory first-time experience with the @azure/identity
package.
In the 2.0 release of @azure/identity
, we’ve introduced a plugin API and two plugin packages. The new plugin architecture allows us to deliver an @azure/identity
package that’s free of NMC dependencies by default—not even “optional” or “peer” dependencies. However, it also allows us to support use cases that rely on NMC implementations through plugin packages. The plugin packages encapsulate these NMC implementations, and can be used in tandem with the @azure/identity
package to augment its functionality and include those features.
Developer Note: The plugin packages were originally classified as “extension” packages. After all, they “extend” the functionality of the @azure/identity
package. Through UX studies and testing, we learned that this “extension” terminology could be confusing. Study participants often confused the @azure/identity-vscode
package with an “extension” of VS Code itself. VS Code uses the same term to describe its marketplace extensions. As a result, we decided to use the term “plugin” instead, to reduce this confusion, especially as one of our plugin packages relates to VS Code!
Use a plugin package
All plugin packages follow the same basic structure. A new top-level function, named useIdentityPlugin
, is exported from @azure/identity
. Apps can use this function to add a plugin implementation to the @azure/identity
package at runtime. The app code should call this function as early as possible. For example, in the module/script body immediately after importing the @azure/identity
package. The following sample shows the initialization of the @azure/identity-vscode
package (discussed further below):
import { vsCodePlugin } from "@azure/identity-vscode";
import { useIdentityPlugin, DefaultAzureCredential } from "@azure/identity";
// This function should be called once, as soon as possible in the execution flow of the app.
useIdentityPlugin(vsCodePlugin);
// Now, my app is augmented with the features of the VSCode plugin, which enables `DefaultAzureCredential` to
// search the VS Code Azure Account extension's token cache and use its session.
async function main() {
const credential = new DefaultAzureCredential();
// Use the credential to authenticate a service client from an Azure SDK package, such as `@azure/storage-blob`.
}
main().catch((error) => {
console.error(error);
process.exit(1);
})
@azure/identity-vscode
This plugin enables VisualStudioCodeCredential
, which relies on keytar
to search the VS Code Azure Account extension’s token cache and use its stored session. Without this plugin, VisualStudioCodeCredential
instances will throw an error that directs the reader to install it. Since VisualStudioCodeCredential
is part of the DefaultAzureCredential
chain, this plugin also enables VS Code Azure Account authentication in DefaultAzureCredential
instances. Previously, we only required that you install the keytar
package. As such, this breaking change in @azure/identity
2.0 requires a change to your app code to continue using this credential type.
Before
import { VisualStudioCodeCredential } from "@azure/identity";
async function main() {
const credential = new VisualStudioCodeCredential();
// Somewhere in the execution of your app, `credential.getToken` will be called, and it will throw an error.
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
With the previous iteration of the @azure/identity
package, this app would execute as expected as long as the keytar
package is available. In the new iteration, this app yields the following error message:
CredentialUnavailableError: No implementation of `VisualStudioCodeCredential` is available. You must install the identity-vscode plugin package (`npm install --save-dev @azure/identity-vscode`) and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling `useIdentityPlugin(vsCodePlugin)` before creating a `VisualStudioCodeCredential`.
at VisualStudioCodeCredential.getToken (.../node_modules/@azure/identity/src/credentials/visualStudioCodeCredential.ts:184:13)
After
To resolve this error, follow the instructions in the error message by:
- Installing the
@azure/identity-vscode
package.npm install --save-dev @azure/identity-vscode
- Importing
useIdentityPlugin
from@azure/identity
. - Importing
vsCodePlugin
from@azure/identity-vscode
. - Calling
useIdentityPlugin(vsCodePlugin)
.
import { vsCodePlugin } from "@azure/identity-vscode";
import { useIdentityPlugin, VisualStudioCodeCredential } from "@azure/identity";
useIdentityPlugin(vsCodePlugin);
async function main() {
const credential = new VisualStudioCodeCredential();
// Somewhere in the execution of your app, `credential.getToken` will be called, and it will now work as expected.
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
@azure/identity-cache-persistence
A second plugin package was added that enables persistent (between process sessions) caching of access tokens. The plugin allows a credential to reuse tokens from a previous Node.js instance. As a result, the authentication flow isn’t repeated. The tokens are placed in a secure store that requires NMC to access. The store’s location and configuration is defined by the host operating system:
- On Windows, it uses a file that is encrypted using the Windows Data Protection API (DPAPI).
- On macOS, it uses the macOS Keychain.
- On Linux, it uses
libsecret
, which will itself use a secure store such as the system keyring (depending on the system configuration).
This capability can reduce:
- The number of times the authentication flow is required while using the app.
- Excessive authentication requests when an app starts if a previous instance’s tokens can be reused.
Persistent token caching is an opt-in feature. It’s enabled by using the @azure/identity-cache-persistence
plugin package:
import { useIdentityPlugin, DeviceCodeCredential } from "@azure/identity";
import { cachePersistencePlugin } from "@azure/identity-cache-persistence";
useIdentityPlugin(cachePersistencePlugin);
async function main() {
// DeviceCodeCredential has an interactive authentication flow, so it will be useful to re-use a pre-existing token
// if one exists. If we don't use token cache persistence, a developer/user will have to enter the code into a web
// page once every time the app starts.
const credential = new DeviceCodeCredential({
tokenCachePersistenceOptions: {
// This option must be set to `true` to enable the feature
enabled: true,
// If the following option is set to `true`, the access tokens may be stored in an UNSAFE, UNENCRYPTED file.
// ONLY ENABLE THIS IF YOU'RE SURE YOU WANT IT.
// unsafeAllowUnencryptedStorage: false,
// The cache persistence plugin supports multiple namespaces. If you provide a `name` for the cache, it can only
// use tokens from other credentials that used the same `name`.
// name: "myCustomCacheName"
}
});
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
Note: If tokenCachePersistenceOptions
are provided without installing and using cachePersistencePlugin
, the app yields an error similar to the one above for the VS Code Azure Account extension:
Error: Persistent token caching was requested, but no persistence provider was configured. You must install the identity-cache-persistence plugin package (`npm install --save @azure/identity-cache-persistence`) and enable it by importing `useIdentityPlugin` from `@azure/identity` and calling `useIdentityPlugin(cachePersistencePlugin)` before using `tokenCachePersistenceOptions`.
at new MsalNode (.../node_modules/@azure/identity/src/msal/nodeFlows/nodeCommon.ts:93:13)
at new MsalDeviceCode (.../node_modules/@azure/identity/src/msal/nodeFlows/msalDeviceCode.ts:28:5)
at new DeviceCodeCredential (.../node_modules/@azure/identity/src/credentials/deviceCodeCredential.ts:52:21)
Summary
The version 2.0 release of @azure/identity
contributes to an excellent Azure SDK developer and end-user experience. We created the Azure Identity library as a central, turnkey authentication solution for the Azure SDK. The new plugin architecture and packages enable an even smoother first-use experience. Apps can still opt in to features provided by NMC modules without creating a true dependency on them. These changes grew out of feedback from customers like you who use the Azure SDK for JavaScript to build amazing apps and services. For more information, see the README files corresponding to each of the relevant packages:
Azure SDK Blog Contributions
Thanks for reading this Azure SDK blog post. We hope you learned something new, and we welcome you to share the post. We’re open to Azure SDK blog contributions from our readers. To get started, contact us at azsdkblog@microsoft.com with your idea, and we’ll set you up as a guest blogger.
- Azure SDK Website: aka.ms/azsdk
- Azure SDK Intro (3-minute video): aka.ms/azsdk/intro
- Azure SDK Intro Deck (PowerPoint deck): aka.ms/azsdk/intro/deck
- Azure SDK Releases: aka.ms/azsdk/releases
- Azure SDK Blog: aka.ms/azsdk/blog
- Azure SDK Twitter: twitter.com/AzureSDK
- Azure SDK Design Guidelines: aka.ms/azsdk/guide
- Azure REST API Guidelines: aka.ms/azapi/guidelines
- Azure SDKs & Tools: azure.microsoft.com/downloads
- Azure SDK Central Repository: github.com/azure/azure-sdk
- Azure SDK for .NET: github.com/azure/azure-sdk-for-net
- Azure SDK for Java: github.com/azure/azure-sdk-for-java
- Azure SDK for Python: github.com/azure/azure-sdk-for-python
- Azure SDK for JavaScript/TypeScript: github.com/azure/azure-sdk-for-js
- Azure SDK for Android: github.com/Azure/azure-sdk-for-android
- Azure SDK for iOS: github.com/Azure/azure-sdk-for-ios
- Azure SDK for Go: github.com/Azure/azure-sdk-for-go
- Azure SDK for C: github.com/Azure/azure-sdk-for-c
- Azure SDK for C++: github.com/Azure/azure-sdk-for-cpp
0 comments