-
Notifications
You must be signed in to change notification settings - Fork 1.9k
feat(auth): add Entra ID identity provider integration for Redis client authentication #2877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Introduce new credential providers: AsyncCredentialsProvider, StreamingCredentialsProvider - Update client handshake process to use the new CredentialsProviders and to support async credentials fetch / credentials refresh - Internal conversion of username/password to a CredentialsProvider - Modify URL parsing to accommodate the new authentication structure - Tests
6302566 to
cb2e186
Compare
cb2e186 to
332eb85
Compare
|
Note: I'm considering adding a export interface SyncCredentialsProvider {
readonly type: 'sync-credentials-provider';
credentials: () => BasicAuth
}
Would appreciate thoughts on whether this negligible performance optimization is worth the additional API surface area. |
332eb85 to
a31045c
Compare
dhensby
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks lovely, and much more thorough and thought-out than my minimal-effort approach in #2849
❤️
| import { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager'; | ||
| export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| import { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager'; | |
| export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError }; | |
| export { TokenManager, TokenManagerConfig, TokenStreamListener, RetryPolicy, IDPError } from './token-manager'; |
I believe these import/export calls can be unified - though this may be a style-guide/preference thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhensby Sure, it makes total sense to unify them.
The idea behind the 'barrel' file initially was to create a proper export so users can import from @redis/client/authx :
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./authx": {
"types": "./dist/lib/client/authx/index.d.ts",
"default": "./dist/lib/client/authx/index.js"
},But then I found out that we already have imports in peer packages using paths like @redis/client/lib/ and even @redis/client/dist/ and many others... This can be addressed in one of these ways:
- Adding more explicit exports (not ideal):
"./index": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./authx": {
"types": "./dist/lib/client/authx/index.d.ts",
"default": "./dist/lib/client/authx/index.js"
},
"./lib/commands/generic-transformers": {
"types": "./dist/lib/commands/generic-transformers.d.ts",
"default": "./dist/lib/commands/generic-transformers.js"
},
"./dist/*": {
"types": "./dist/*.d.ts",
"default": "./dist/*.js"
},
"./lib/errors": {
"types": "./dist/lib/errors.d.ts",
"default": "./dist/lib/errors.js"
}- Not using exports at all, keeping it as is and creating a barrel file just for user convenience
- Creating a separate submodule containing only the authx support classes
For now, I've decided to stick with not using exports, but I'm considering creating a separate submodule for the authx support classes.
| /** | ||
| * Helper function to delay execution for a given number of milliseconds. | ||
| * @param ms | ||
| */ | ||
| const delay = (ms: number) => { | ||
| return new Promise(resolve => setTimeout(resolve, ms)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
async setTimeout is now built into node, there used to be a utility in redis for this which I think was removed in preference of the built-in functionality which is being used extensively in other tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @dhensby! I'll switch to using the built-ins
|
|
||
| describe('error scenarios', () => { | ||
| it('should not recover if retries are not enabled', async () => { | ||
| const clock = new FakeClock(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
node allows synthetic clocks, so it may be preferred to use them over a custom faked clock?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @dhensby! You're the second node developer to suggest using node's synthetic timers. While I have a slight preference for avoiding global method replacements like setTimeout/Date.now() , you're right - it would be better to align with common practices. I'll switch to using Node's synthetic timers instead of my custom Clock approach.
| @@ -0,0 +1,103 @@ | |||
| import {Disposable} from './types'; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be worth using TS 5.2 "native" Disposable interface (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#using-declarations-and-explicit-resource-management)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dhensby makes total sense, i will use the built-in Disposable, thanks for the tip!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Symbol.dispose is not meant to be called directly, but to be used together with using and automatically called when the "using variable" goes out of scope (see the example from the typescript article). I don't think it fits here..
see https://github.com/tc39/proposal-explicit-resource-management for more details..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That isn't my interpretation of the spec (regarding not calling it directly). In fact it has this comment (emphasis mine):
Explicit Resource Management — Indicates a system whereby the lifetime of a "resource" is managed explicitly by the user either imperatively (by directly calling a method like Symbol.dispose) or declaratively (through a block-scoped declaration like using).[1]
[1]https://github.com/tc39/proposal-explicit-resource-management?tab=readme-ov-file#definitions
Preventing direct calls of the dispose method would be problematic for polyfills and also nested disposal of resources.
However, you are right that the using keyword will dispose of the resource when the variable falls out of the scope, so cleanup will need to be imperative rather than declarative. My recommendation was to use the native Dispose interface rather than re-implementing it idiosyncratically, which may be confusing given the interface and behaviour is defined in typescript already.
I don't think there is any need for a |
@dhensby I agree - I don't think adding a |
a31045c to
ce0fd1f
Compare
Introduces TokenManager and supporting classes to handle token acquisition, automatic refresh, and updates via identity providers. This foundation enables consistent authentication token management across different identity provider implementations. Key additions: - Add TokenManager to obtain and maintain auth tokens from identity providers with automated refresh scheduling based on TTL and configurable thresholds - Add IdentityProvider interface for token acquisition from auth providers - Implement Token class for managing token state and TTL tracking - Include configurable retry mechanism with exponential backoff and jitter - Add comprehensive test suite covering refresh cycles and error handling This change establishes the core infrastructure needed for reliable token lifecycle management across different authentication providers.
bc8d1fe to
d0cd508
Compare
Introduces Entra ID (former Azure AD) authentication support with multiple authentication flows and automated token lifecycle management. Key additions: - Add EntraIdCredentialsProvider for handling Entra ID authentication flows - Implement MSALIdentityProvider to integrate with MSAL/EntraID authentication library - Add support for multiple authentication methods: - Managed identities (system and user-assigned) - Client credentials with certificate - Client credentials with secret - Authorization Code flow with PKCE - Add factory class with builder methods for each authentication flow - Include sample Express server implementation for Authorization Code flow - Add comprehensive configuration options for authority and token management
d0cd508 to
0ce5e7a
Compare
- Add support for configuring replica authentication with 'masterauth' - Allow default client configuration during test cluster creation This improves the testing framework's flexibility by automatically configuring replica authentication when '--requirepass' is used and enabling custom client configurations across cluster nodes.
2d82e6b to
b326302
Compare
98667ef to
c37d42d
Compare
32fbf6f to
5fa5406
Compare
5fa5406 to
1173864
Compare
- Add integration tests for token renewal and re-authentication flows - Update credentials provider to use uniqueId as username instead of account username - Add test utilities for loading Redis endpoint configurations - Split TypeScript configs into separate files for samples and integration tests - Remove `@redis/authx` package and nest it under `@`
1173864 to
bcc4bc3
Compare
dmaier-redislabs
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good for me. We are going to release as pre-release first.
|
Hey @dmaier-redislabs, @bobymicroby any ETA when pre-release is planned? |
|
Hey @taraspos, We are currently working on adding more documentation and improving module exports. Stay tuned for upcoming updates. |
…nt authentication (redis#2877) * feat(auth): refactor authentication mechanism to use CredentialsProvider - Introduce new credential providers: AsyncCredentialsProvider, StreamingCredentialsProvider - Update client handshake process to use the new CredentialsProviders and to support async credentials fetch / credentials refresh - Internal conversion of username/password to a CredentialsProvider - Modify URL parsing to accommodate the new authentication structure - Tests * feat(auth): auth extensions Introduces TokenManager and supporting classes to handle token acquisition, automatic refresh, and updates via identity providers. This foundation enables consistent authentication token management across different identity provider implementations. Key additions: - Add TokenManager to obtain and maintain auth tokens from identity providers with automated refresh scheduling based on TTL and configurable thresholds - Add IdentityProvider interface for token acquisition from auth providers - Implement Token class for managing token state and TTL tracking - Include configurable retry mechanism with exponential backoff and jitter - Add comprehensive test suite covering refresh cycles and error handling This change establishes the core infrastructure needed for reliable token lifecycle management across different authentication providers. * feat(auth): add Entra ID identity provider integration Introduces Entra ID (former Azure AD) authentication support with multiple authentication flows and automated token lifecycle management. Key additions: - Add EntraIdCredentialsProvider for handling Entra ID authentication flows - Implement MSALIdentityProvider to integrate with MSAL/EntraID authentication library - Add support for multiple authentication methods: - Managed identities (system and user-assigned) - Client credentials with certificate - Client credentials with secret - Authorization Code flow with PKCE - Add factory class with builder methods for each authentication flow - Include sample Express server implementation for Authorization Code flow - Add comprehensive configuration options for authority and token management * feat(test-utils): improve cluster testing - Add support for configuring replica authentication with 'masterauth' - Allow default client configuration during test cluster creation This improves the testing framework's flexibility by automatically configuring replica authentication when '--requirepass' is used and enabling custom client configurations across cluster nodes. * feat(auth): add EntraId integration tests - Add integration tests for token renewal and re-authentication flows - Update credentials provider to use uniqueId as username instead of account username - Add test utilities for loading Redis endpoint configurations - Split TypeScript configs into separate files for samples and integration tests - Remove `@redis/authx` package and nest it under `@`
Description
This PR adds Microsoft Entra ID (formerly Azure AD) authentication support to node-redis through:
@redis/entraidpackage providing:StreamingCredentialsProviderimplementation for EntraIDCredentialsProviderinterface for async and streaming credentialsTokenManagerand support classes for automated token lifecycle managementThis enables Redis Enterprise customers to authenticate using Entra ID identities. The architecture also allows custom
CredentialProviderimplementations for third-party Identity Provider integration.Checklist
[x] npm test passes (new tests added for token management / streaming credential provider )
[ ] New code is mostly tested, except for some pending test coverage in the EntraID package.
[ ] docs are in progress