Repository navigation
feat(node): add auto-refresh - #12
Conversation
Signed-off-by: Edward Liang <liawedwa@amazon.com>
Signed-off-by: Edward Liang <liawedwa@amazon.com>
Signed-off-by: Edward Liang <liawedwa@amazon.com>
Signed-off-by: Edward Liang <liawedwa@amazon.com>
| * the background, so every new client is created with a valid token without | ||
| * signing a new one per connection. Automatic reconnects are disabled because | ||
| * they would reuse the token the connection was opened with; long-running | ||
| * applications should create a replacement client, calling getCredentials() |
There was a problem hiding this comment.
nit: since iovalkey only takes a static password, this example still has to disable reconnects, so the manager's main benefit isn't visible. Could we add a second example with node-redis v5, whose credentialsProvider: { type: "async-credentials-provider", credentials: () => auth.getCredentials().then(([username, password]) => ({ username, password })) } is called on every connect and reconnect? Keep this one as the static-password variant.
| } | ||
|
|
||
| const cached = this.cached; | ||
| if (cached && this.now() < cached.expiresAt) { |
There was a problem hiding this comment.
A cached token is served right up to expiresAt, so a caller can receive one with a few hundred ms left and fail AUTH once we add network latency into account. how about we add a serve margin, e.g. treat the token as expired ~20 s early (expiresAt = issuedAt + (TTL − margin) * 1000) so callers block on the refresh instead?
| // but it has expired, throw a TokenRefreshError with the last error as its | ||
| // cause. | ||
| if (cached && this.now() < cached.expiresAt) { | ||
| this.scheduleRefresh(MAX_DELAY_MS); |
There was a problem hiding this comment.
non-blocking: the 5 sec pause after a failed cycle only holds while nothing calls getToken(), this line starts a new cycle on any request past refreshAt, so under a reconnect storm we retry back-to-back against a credential source that's already struggling. Callers are unaffected (they keep getting the cached token)
| cancelSleep?.(); | ||
| } | ||
|
|
||
| private refresh(): Promise<string> { |
There was a problem hiding this comment.
Could this be public (with the cache invalidated first)? After a WRONGPASS the client currently has no way to drop the cached token, so the manager adds up to 300 sec of serving a rejected token on top of whatever the credential chain does. It won't fix every auth failure, but it stops the cache from making recovery slower than the stateless provider. GLIDE exposes refresh_token() for this.
There was a problem hiding this comment.
added refreshToken()
Signed-off-by: Edward Liang <liawedwa@amazon.com>
Summary
Adds
ElastiCacheIAMAuthTokenManagerfor applications that need to reuse an IAM auth token across connections and refresh it before expiry. The existingElastiCacheIAMAuthTokenProviderremains stateless and continues to mint a new token for everygetToken()call.What's in it
node/src/token-manager.tsElastiCacheIAMAuthTokenManager, configurable refresh timing, single-flight initial mints, background refresh, retry backoff, token-change callbacks, and explicit cleanup throughclose().node/src/errors.ts,node/src/index.tsTokenRefreshErrorand the token-manager API/types.node/src/token-generator.tsensureRegionResolved()so manager creation can fail early when region resolution fails.node/test/getCredentials().node/README.md,node/examples/connect-iovalkey.mjs,node/CHANGELOG.mdDesign decisions
The manager mints lazily through either
getToken()orgetCredentials(). Concurrent callers share one initial mint.Refresh starts at
refreshAfterSecondsand makes up to eight attempts with jittered exponential backoff. If the cached token remains valid, callers keep receiving it while retries continue. Once it expires, failed refreshes throwTokenRefreshError, which intentionally extendsErrorrather thanToolkitInputError.getCredentials()returns the normalized user ID with the cached token for clients that accept a no-argument credential-provider hook.Tests
node --test dist-test/test/token-manager.test.js— passed, 17/17 tests.npm test— build completed; 80/81 tests passed. The packed-package installation test was killed withSIGTERMwhilenpm installattempted to access the npm registry.Not in this PR
The manager refreshes credentials for newly created clients; it does not re-authenticate an existing iovalkey connection. Applications still need to create a replacement client after a connection is lost.