Skip to content

Commit 8056f36

Browse files
Merge pull request #1306 from redis/DOC-4989-amr-javascript
DOC-4989 added node-js AMR page
2 parents 38020a8 + ff00a22 commit 8056f36

File tree

1 file changed

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

1 file changed

+363
-0
lines changed

content/develop/clients/nodejs/amr.md

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
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"
36+
npm install "@redis/entraid"
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';
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
103+
an error occurs. 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+
This function classifies errors from the identity provider as
124+
retryable (returning `true`) or non-retryable (returning `false`).
125+
Implement your own custom logic here to determine if a token refresh failure
126+
should be retried, based on the type of error. For example, a refresh failure
127+
caused by a transient network error would probably succeed eventually if you retry
128+
it, but an invalid certificate is generally a fatal error. If you don't supply a custom
129+
function in this parameter, the default behavior is to retry all types of errors.
130+
131+
#### **authorityConfig**
132+
133+
The `authorityConfig` object has a `type` field that can take any of
134+
the string values `default`, `multi-tenant`, or `custom`. If you use
135+
`multi-tenant` then you must also supply a `tenantId` field containing
136+
the tenant ID string:
137+
138+
```js
139+
// Other fields...
140+
authorityConfig: {
141+
type: 'multi-tenant',
142+
tenantId: 'your-tenant-id'
143+
},
144+
// ...
145+
```
146+
147+
If you use `custom` then you must also supply an `authorityUrl`
148+
containing the authority URL string:
149+
150+
```js
151+
// Other fields...
152+
authorityConfig: {
153+
type: 'custom',
154+
authorityUrl: 'your-authority-url'
155+
},
156+
// ...
157+
```
158+
See Microsoft's [Authority]([Authority](https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-application-configuration#authority))
159+
docs for more information.
160+
161+
### Authenticate with a service principal
162+
163+
Use the `createForClientCredentials()` factory function to create a
164+
credentials provider that authenticates to AMR using a
165+
service principal (see the
166+
[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals) to learn more about service principals).
167+
168+
You will need the following details of your service principal to make the connection:
169+
170+
- Client ID
171+
- Client secret
172+
- Tenant ID
173+
174+
The example below shows how to call `createForClientCredentials()`. Note that the
175+
[parameter object](#provider-parameters) includes an extra field here for the
176+
client secret.
177+
178+
```js
179+
const provider = EntraIdCredentialsProviderFactory.createForClientCredentials({
180+
clientId: 'your-client-id',
181+
clientSecret: 'your-client-secret',
182+
authorityConfig: {
183+
type: 'multi-tenant',
184+
tenantId: 'your-tenant-id'
185+
},
186+
tokenManagerConfig: {
187+
expirationRefreshRatio: 0.8 // Refresh token after 80% of its lifetime
188+
}
189+
});
190+
```
191+
192+
If you want to authenticate using a service principal with a certificate,
193+
use `createForClientCredentialsWithCertificate()` to create the credentials
194+
provider. This is similar to `createForClientCredentials()` but it takes
195+
a `clientCertificate` parameter object instead of the `clientSecret` parameter.
196+
This object has the following string fields:
197+
198+
- `x5c`: X.509 certificate.
199+
- `privateKey`: The certificate's private key.
200+
- `thumbprintSha256`: (Optional) SHA-256 hash of the certificate.
201+
202+
The example below shows how to call `createForClientCredentialsWithCertificate()` and
203+
demonstrates the `retry` parameter in `tokenManagerConfig`:
204+
205+
```js
206+
const provider = EntraIdCredentialsProviderFactory.createForClientCredentialsWithCertificate({
207+
clientId: 'your-client-id',
208+
clientCertificate: {
209+
x5c: '<certificate>',
210+
privateKey: '<private-key>',
211+
thumbprintSha256: '<certificate-SHA-256-hash>'
212+
},
213+
tokenManagerConfig: {
214+
expirationRefreshRatio: 0.75,
215+
retry: {
216+
maxAttempts: 3,
217+
initialDelayMs: 100,
218+
maxDelayMs: 1000,
219+
backoffMultiplier: 2
220+
}
221+
}
222+
});
223+
```
224+
225+
### Authenticate with a managed identity
226+
227+
You can authenticate to AMR using a managed identity (see the
228+
[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) to learn more about managed identities).
229+
230+
For a system-assigned managed identity, use the `createForSystemAssignedManagedIdentity()` factory function as shown in the example below:
231+
232+
```js
233+
const provider = EntraIdCredentialsProviderFactory.createForSystemAssignedManagedIdentity({
234+
clientId: 'your-client-id'
235+
});
236+
```
237+
238+
For a user-assigned managed identity, use `createForUserAssignedManagedIdentity()`.
239+
Here, the [parameter object](#provider-parameters) includes an extra field for
240+
the user-assigned client ID.
241+
242+
```js
243+
const provider = EntraIdCredentialsProviderFactory.createForUserAssignedManagedIdentity({
244+
clientId: 'your-client-id',
245+
userAssignedClientId: 'your-user-assigned-client-id'
246+
});
247+
```
248+
249+
### Auth code flow with PKCE
250+
251+
*Auth code flow with Proof Key for Code Exchange (PKCE)* lets a client app
252+
authenticate for access to web APIs and other restricted resources. This
253+
requires a redirect URI to return control to your app after authentication.
254+
See
255+
[Microsoft identity platform and OAuth 2.0 authorization code flow](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow)
256+
for more information.
257+
258+
Use the `createForAuthorizationCodeWithPKCE()` factory method to use auth code flow
259+
with PKCE. The example below shows the extra field `redirectUri` in the parameter
260+
object:
261+
262+
```js
263+
const provider = EntraIdCredentialsProviderFactory.createForAuthorizationCodeWithPKCE({
264+
clientId: 'your-client-id',
265+
redirectUri: '<uri-for-your-app>'
266+
});
267+
```
268+
269+
### Authenticate with `DefaultAzureCredential` {#def-az-cred}
270+
271+
The
272+
[`DefaultAzureCredential`](https://learn.microsoft.com/en-gb/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#defaultazurecredential-overview)
273+
class in `@azure/identity` is designed for use during development. It simplifies
274+
authentication by automatically trying different credentials until one succeeds.
275+
See [`DefaultAzureCredential` overview](https://learn.microsoft.com/en-gb/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#defaultazurecredential-overview)
276+
in the Microsoft docs for more information.
277+
278+
The example below shows how to use `createForDefaultAzureCredential()`:
279+
280+
```js
281+
import { DefaultAzureCredential } from '@azure/identity';
282+
import { EntraIdCredentialsProviderFactory, REDIS_SCOPE_DEFAULT }
283+
from '@redis/entraid';
284+
285+
// ...
286+
287+
// Create a DefaultAzureCredential instance
288+
const credential = new DefaultAzureCredential();
289+
290+
// Create a provider using DefaultAzureCredential
291+
const provider = EntraIdCredentialsProviderFactory.createForDefaultAzureCredential({
292+
// Use the same parameters you would pass to credential.getToken()
293+
credential,
294+
scopes: REDIS_SCOPE_DEFAULT, // The Redis scope
295+
// Optional additional parameters for getToken
296+
options: {
297+
// Any options you would normally pass to credential.getToken()
298+
},
299+
tokenManagerConfig: {
300+
expirationRefreshRatio: 0.8
301+
}
302+
});
303+
```
304+
305+
Note that when you use `createForDefaultAzureCredential()`, you must:
306+
307+
- Create your own instance of `DefaultAzureCredential`.
308+
- Pass the same parameters to the factory method that you would use with the `getToken()`
309+
method:
310+
- `scopes`: The Redis scope (use the exported `REDIS_SCOPE_DEFAULT` constant).
311+
- `options`: Any other options for the `getToken()` method.
312+
313+
## Connect
314+
315+
When you have created your credential provider instance, you are ready to
316+
connect to AMR.
317+
The example below shows how to pass the instance as a parameter to the standard
318+
`createClient()` connection method.
319+
320+
```js
321+
import { createClient } from '@redis/client';
322+
import { EntraIdCredentialsProviderFactory }
323+
from '@redis/entraid';
324+
325+
// Create credentials provider instance...
326+
327+
const client = createClient({
328+
url: 'redis://localhost',
329+
credentialsProvider: provider
330+
});
331+
332+
await client.connect();
333+
334+
const size = await client.dbSize();
335+
console.log(`Database size is ${size}`);
336+
```
337+
338+
## RESP2 PUB/SUB limitations
339+
340+
If you are using the
341+
[RESP2]({{< relref "/develop/reference/protocol-spec#resp-versions" >}})
342+
protocol, you should
343+
be aware that [pub/sub]({{< relref "/develop/interact/pubsub" >}}) can
344+
cause complications with reauthentication.
345+
346+
After a connection enters PUB/SUB mode, the socket is blocked and can't process
347+
out-of-band commands like [`AUTH`]({{< relref "/commands/auth" >}}). This means that
348+
connections in PUB/SUB mode can't be reauthenticated when the tokens are refreshed.
349+
As a result, PUB/SUB connections will be evicted by the Redis proxy when their tokens expire.
350+
You must reconnect with fresh tokens when this happens.
351+
352+
## Note about transactions
353+
354+
If you use
355+
[transactions](https://redis.io/docs/latest/develop/clients/nodejs/transpipe)
356+
in code that also uses token-based authentication, ensure that you use
357+
the `node-redis` client multi/exec API rather than explicit commands to create
358+
each transaction (see
359+
[Execute a transaction](https://redis.io/docs/latest/develop/clients/nodejs/transpipe/#execute-a-transaction)
360+
for an example of correct usage).
361+
This is because the token manager might attempt to reauthenticate while your code
362+
issues the separate transaction commands, which will interfere with the transaction.
363+
The transaction API handles this case for you safely.

0 commit comments

Comments
 (0)