Skip to content

Commit f2901f1

Browse files
DOC-4989 added node-js AMR page
1 parent 29f35d9 commit f2901f1

File tree

1 file changed

+361
-0
lines changed
  • content/develop/clients/nodejs

1 file changed

+361
-0
lines changed

content/develop/clients/nodejs/amr.md

Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
---
2+
categories:
3+
- docs
4+
- develop
5+
- stack
6+
- oss
7+
- rs
8+
- rc
9+
- oss
10+
- kubernetes
11+
- clients
12+
description: Learn how to authenticate to an Azure Managed Redis (AMR) database
13+
linkTitle: Connect to AMR
14+
title: Connect to Azure Managed Redis
15+
weight: 2
16+
---
17+
18+
The [`@redis/entraid`](https://github.com/redis/node-redis/tree/master/packages/entraid)
19+
package lets you authenticate your app to
20+
[Azure Managed Redis (AMR)](https://azure.microsoft.com/en-us/products/managed-redis)
21+
using [Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity/).
22+
You can authenticate using a system-assigned or user-assigned
23+
[managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview),
24+
a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals),
25+
an [auth code flow](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow),
26+
or a [`DefaultAzureCredential`](https://learn.microsoft.com/en-gb/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#defaultazurecredential-overview) instance.
27+
The `@redis/entraid` code fetches and renews the authentication tokens for you automatically.
28+
29+
## Install
30+
31+
Install [`node-redis`]({{< relref "/develop/clients/nodejs" >}}) and
32+
`@redis/entraid` with the following commands:
33+
34+
```bash
35+
npm install "@redis/client@5.0.0-next.6"
36+
npm install "@redis/entraid@5.0.0-next.6"
37+
```
38+
39+
## Create a credentials provider instance
40+
41+
A credentials provider object obtains the authentication credentials you
42+
need when you connect to Redis (see the [Connect](#connect) section below
43+
for a connection example). The `EntraIdCredentialsProviderFactory`
44+
class provides a factory method for each type of credentials provider.
45+
Import `EntraIdCredentialsProviderFactory` with the following code:
46+
47+
```js
48+
import { EntraIdCredentialsProviderFactory }
49+
from '@redis/entraid/dist/lib/entra-id-credentials-provider-factory';
50+
```
51+
52+
Then, use the appropriate factory method to create your credentials provider:
53+
54+
- Use [`createForClientCredentials()`](#authenticate-with-a-service-principal)
55+
to authenticate with a service principal using a client secret.
56+
- Use [`createForClientCredentialsWithCertificate()`](#authenticate-with-a-service-principal)
57+
to authenticate with a service principal using a certificate.
58+
- Use [`createForSystemAssignedManagedIdentity()`](#authenticate-with-a-managed-identity)
59+
to authenticate with a system-assigned managed identity.
60+
- Use [`createForUserAssignedManagedIdentity()`](#authenticate-with-a-managed-identity)
61+
to authenticate with a user-assigned managed identity.
62+
- Use [`createForAuthorizationCodeWithPKCE()`](#auth-code-flow-with-pkce)
63+
for interactive authentication flows in user applications.
64+
- Use [`createForDefaultAzureCredential()`](#def-az-cred)
65+
to authenticate with Azure Identity's `DefaultAzureCredential` class.
66+
67+
The sections below describe these factory functions in more detail.
68+
69+
### Provider parameters
70+
71+
All these factory functions receive an object containing the parameters
72+
to create the credentials provider. The object generally contains the following
73+
fields, but specific factory methods add or omit particular parameters:
74+
75+
- `clientId`: A string containing the client ID.
76+
- `scopes`: (Optional) A string or an array of strings defining the
77+
[scopes](https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc)
78+
you want to apply. Configure your client application to acquire a Microsoft Entra token for scope, https://redis.azure.com/.default or acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default with the
79+
[Microsoft Authentication Library (MSAL)](https://learn.microsoft.com/en-us/entra/identity-platform/msal-overview). Note that the `entra-id-credentials-provider-factory`
80+
module exports a constant `REDIS_SCOPE_DEFAULT` for the default scope. See the
81+
[`DefaultAzureCredential`](#def-az-cred) example below to learn how to use this.
82+
- `authorityConfig`: (Optional) [Authority](https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-application-configuration#authority)
83+
settings. See the [`authorityConfig`](#authorityconfig) section below for a full
84+
description.
85+
- `tokenManagerConfig`: An object with fields that specify how to refresh the token.
86+
See the [`tokenManagerConfig`](#tokenmanagerconfig) section below for a full
87+
description.
88+
89+
#### **tokenManagerConfig**
90+
91+
You can configure an authentication token to expire after a certain amount of
92+
time, known as its *lifetime*. You must refresh a token before its lifetime
93+
is over to continue using it (see
94+
[Configurable token lifetimes in the Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/configurable-token-lifetimes)
95+
for more information). The `tokenManagerConfig` object lets you pass parameters to
96+
specify how you want to manage token refreshes. The fields of the object are listed
97+
below:
98+
99+
- `expirationRefreshRatio`: This is the fraction of the token's lifetime that should
100+
elapse before a refresh is triggered. For example, a value of 0.75 means the token
101+
should be refreshed when 75% of its lifetime has elapsed.
102+
- `retry`: This object specifies the policy to retry refreshing the token if the
103+
first attempt fails. It has the following fields:
104+
- `maxAttempts`: The maximum number of times to attempt a refresh before
105+
aborting.
106+
- `initialDelayMs`: The delay (in milliseconds) before retrying after the
107+
first failed attempt.
108+
- `maxDelayMs`: The maximum time (in milliseconds) to wait between attempts
109+
to refresh.
110+
- `backoffMultiplier`: The
111+
[exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)
112+
for the time between attempts to refresh. For example, a value of 2
113+
will double the delay for each attempt. Use a value of 1 to keep
114+
the delay roughly constant.
115+
- `jitterPercentage`: (Optional) The maximum fraction of the calculated delay time to
116+
randomly add or subtract. For example, a value of 0.1 will add or subtract
117+
up to 10% of the delay time. This random component helps to prevent
118+
repeated collisions between clients that have the same retry settings.
119+
- `isRetryable`: (Optional) This specifies a function with the signature <br/><br/>
120+
`(error, attempt) => boolean`<br/><br/>
121+
where `error` is the error object from
122+
a failed attempt and `attempt` is the number of attempts previously made.
123+
The `boolean` return value is `true` if another attempt should be made
124+
to refresh the token and `false` otherwise. Implement your own custom
125+
logic in this function to determine when to abort retrying. For example,
126+
you might detect when a particular error is fatal, or vary the number of
127+
attempts depending on the error type.
128+
129+
#### **authorityConfig**
130+
131+
The `authorityConfig` object has a `type` field that can take any of
132+
the string values `default`, `multi-tenant`, or `custom`. If you use
133+
`multi-tenant` then you must also supply a `tenantId` field containing
134+
the tenant ID string:
135+
136+
```js
137+
// Other fields...
138+
authorityConfig: {
139+
type: 'multi-tenant',
140+
tenantId: 'your-tenant-id'
141+
},
142+
// ...
143+
```
144+
145+
If you use `custom` then you must also supply an `authorityUrl`
146+
containing the authority URL string:
147+
148+
```js
149+
// Other fields...
150+
authorityConfig: {
151+
type: 'custom',
152+
authorityUrl: 'your-authority-url'
153+
},
154+
// ...
155+
```
156+
See Microsoft's [Authority]([Authority](https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-application-configuration#authority))
157+
docs for more information.
158+
159+
### Authenticate with a service principal
160+
161+
Use the `createForClientCredentials()` factory function to create a
162+
credentials provider that authenticates to AMR using a
163+
service principal (see the
164+
[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals) to learn more about service principals).
165+
166+
You will need the following details of your service principal to make the connection:
167+
168+
- Client ID
169+
- Client secret
170+
- Tenant ID
171+
172+
The example below shows how to call `createForClientCredentials()`. Note that the
173+
[parameter object](#provider-parameters) includes an extra field here for the
174+
client secret.
175+
176+
```js
177+
const provider = EntraIdCredentialsProviderFactory.createForClientCredentials({
178+
clientId: 'your-client-id',
179+
clientSecret: 'your-client-secret',
180+
authorityConfig: {
181+
type: 'multi-tenant',
182+
tenantId: 'your-tenant-id'
183+
},
184+
tokenManagerConfig: {
185+
expirationRefreshRatio: 0.8 // Refresh token after 80% of its lifetime
186+
}
187+
});
188+
```
189+
190+
If you want to authenticate using a service principal with a certificate,
191+
use `createForClientCredentialsWithCertificate()` to create the credentials
192+
provider. This is similar to `createForClientCredentials()` but it takes
193+
a `clientCertificate` parameter object instead of the `clientSecret` parameter.
194+
This object has the following string fields:
195+
196+
- `x5c`: X.509 certificate.
197+
- `privateKey`: The certificate's private key.
198+
- `thumbprintSha256`: (Optional) SHA-256 hash of the certificate.
199+
200+
The example below shows how to call `createForClientCredentialsWithCertificate()` and
201+
demonstrates the `retry` parameter in `tokenManagerConfig`:
202+
203+
```js
204+
const provider = EntraIdCredentialsProviderFactory.createForClientCredentialsWithCertificate({
205+
clientId: 'your-client-id',
206+
clientCertificate: {
207+
x5c: '<certificate>',
208+
privateKey: '<private-key>',
209+
thumbprintSha256: '<certificate-SHA-256-hash>'
210+
},
211+
tokenManagerConfig: {
212+
expirationRefreshRatio: 0.75,
213+
retry: {
214+
maxAttempts: 3,
215+
initialDelayMs: 100,
216+
maxDelayMs: 1000,
217+
backoffMultiplier: 2
218+
}
219+
}
220+
});
221+
```
222+
223+
### Authenticate with a managed identity
224+
225+
You can authenticate to AMR using a managed identity (see the
226+
[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) to learn more about managed identities).
227+
228+
For a system-assigned managed identity, use the `createForSystemAssignedManagedIdentity()` factory function as shown in the example below:
229+
230+
```js
231+
const provider = EntraIdCredentialsProviderFactory.createForSystemAssignedManagedIdentity({
232+
clientId: 'your-client-id'
233+
});
234+
```
235+
236+
For a user-assigned managed identity, use `createForUserAssignedManagedIdentity()`.
237+
Here, the [parameter object](#provider-parameters) includes an extra field for
238+
the user-assigned client ID.
239+
240+
```js
241+
const provider = EntraIdCredentialsProviderFactory.createForUserAssignedManagedIdentity({
242+
clientId: 'your-client-id',
243+
userAssignedClientId: 'your-user-assigned-client-id'
244+
});
245+
```
246+
247+
### Auth code flow with PKCE
248+
249+
*Auth code flow with Proof Key for Code Exchange (PKCE)* lets a client app
250+
authenticate for access to web APIs and other restricted resources. This
251+
requires a redirect URI to return control to your app after authentication.
252+
See
253+
[Microsoft identity platform and OAuth 2.0 authorization code flow](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow)
254+
for more information.
255+
256+
Use the `createForAuthorizationCodeWithPKCE()` factory method to use auth code flow
257+
with PKCE. The example below shows the extra field `redirectUri` in the parameter
258+
object:
259+
260+
```js
261+
const provider = EntraIdCredentialsProviderFactory.createForAuthorizationCodeWithPKCE({
262+
clientId: 'your-client-id',
263+
redirectUri: '<uri-for-your-app>'
264+
});
265+
```
266+
267+
### Authenticate with `DefaultAzureCredential` {#def-az-cred}
268+
269+
The
270+
[`DefaultAzureCredential`](https://learn.microsoft.com/en-gb/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#defaultazurecredential-overview)
271+
class in `@azure/identity` is designed for use during development. It simplifies
272+
authentication by automatically trying different credentials until one succeeds.
273+
See [`DefaultAzureCredential` overview](https://learn.microsoft.com/en-gb/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#defaultazurecredential-overview)
274+
in the Microsoft docs for more information.
275+
276+
The example below shows how to use `createForDefaultAzureCredential()`:
277+
278+
```js
279+
import { DefaultAzureCredential } from '@azure/identity';
280+
import { EntraIdCredentialsProviderFactory, REDIS_SCOPE_DEFAULT }
281+
from '@redis/entraid/dist/lib/entra-id-credentials-provider-factory';
282+
283+
// ...
284+
285+
// Create a DefaultAzureCredential instance
286+
const credential = new DefaultAzureCredential();
287+
288+
// Create a provider using DefaultAzureCredential
289+
const provider = EntraIdCredentialsProviderFactory.createForDefaultAzureCredential({
290+
// Use the same parameters you would pass to credential.getToken()
291+
credential,
292+
scopes: REDIS_SCOPE_DEFAULT, // The Redis scope
293+
// Optional additional parameters for getToken
294+
options: {
295+
// Any options you would normally pass to credential.getToken()
296+
},
297+
tokenManagerConfig: {
298+
expirationRefreshRatio: 0.8
299+
}
300+
});
301+
```
302+
303+
Note that when you use `createForDefaultAzureCredential()`, you must:
304+
305+
- Create your own instance of `DefaultAzureCredential`.
306+
- Pass the same parameters to the factory method that you would use with the `getToken()`
307+
method:
308+
- `scopes`: The Redis scope (use the exported `REDIS_SCOPE_DEFAULT` constant).
309+
- `options`: Any other options for the `getToken()` method.
310+
311+
## Connect
312+
313+
When you have created your credential provider instance, you are ready to
314+
connect to AMR.
315+
The example below shows how to pass the instance as a parameter to the standard
316+
`createClient()` connection method.
317+
318+
```js
319+
import { createClient } from '@redis/client';
320+
import { EntraIdCredentialsProviderFactory }
321+
from '@redis/entraid/dist/lib/entra-id-credentials-provider-factory';
322+
323+
// Create credentials provider instance...
324+
325+
const client = createClient({
326+
url: 'redis://localhost',
327+
credentialsProvider: provider
328+
});
329+
330+
await client.connect();
331+
332+
const size = await client.dbSize();
333+
console.log(`Database size is ${size}`);
334+
```
335+
336+
## RESP2 PUB/SUB limitations
337+
338+
If you are using the
339+
[RESP2]({{< relref "/develop/reference/protocol-spec#resp-versions" >}})
340+
protocol, you should
341+
be aware that [pub/sub]({{< relref "/develop/interact/pubsub" >}}) can
342+
cause complications with reauthentication.
343+
344+
After a connection enters PUB/SUB mode, the socket is blocked and can't process
345+
out-of-band commands like [`AUTH`]({{< relref "/commands/auth" >}}). This means that
346+
connections in PUB/SUB mode can't be reauthenticated when the tokens are refreshed.
347+
As a result, PUB/SUB connections will be evicted by the Redis proxy when their tokens expire.
348+
You must reconnect with fresh tokens when this happens.
349+
350+
## Note about transactions
351+
352+
If you use
353+
[transactions](https://redis.io/docs/latest/develop/clients/nodejs/transpipe)
354+
in code that also uses token-based authentication, ensure that you use
355+
the `node-js` transaction API rather than explicit commands to create
356+
each transaction (see
357+
[Execute a transaction](https://redis.io/docs/latest/develop/clients/nodejs/transpipe/#execute-a-transaction)
358+
for an example of correct usage).
359+
This is because the token manager might attempt to reauthenticate while your code
360+
issues the separate transaction commands, which will interfere with the transaction.
361+
The transaction API handles this case for you safely.

0 commit comments

Comments
 (0)