How to gracefully refresh accesstoken instead of using static passwords?
How to work with password which expire after some time or that are not present initially?
Microsoft released an example of how to set it up using ioredis, but the problem is that I cannot get it to work as I want.
Global Redis Client
Having only one global redis client and once the access token expires you would need to ensure that it swaps the old instance with a new instance after some period of time, but would such a solution which is suggested in azure-sdk-for-js even work?
- Will the swap cause the old redis client to drop pending commands?
- You would need to ensure that the old client is diconnected gracefully.
- [Issue] The initial client will have incorrect password until it runs out of reconnection attempts and uses the latest changes in the options object. The only way to get around this seem to be to update the redis.options.username/password after a successful auth command.
- How would this work when running in dev?
Local Redis Client
You create an async factory for providing redis clients with the latest password and ensure that the client is freed after it has been used within a small scope. No need to worry about updating the redis options to match the latest password after the access token expires. However, the issue I ran into with this solution is that it eventually ran out of connections. 'ERR max number of clients reached'. Do you have any recommendations for going this route?
// Example
const deleteAccount = async (id: string) => {
const client = await getRedisClientAsync();
try {
const key = getAccountKey(id);
const account = (await loadObjectFromHash(key)) as AdapterAccount;
if (!account.userId) return null;
await client.hdel(key);
await client.del(getAccountByUserIdKey(account.userId));
} finally {
client.quit();
}
};
Question Is there any guidance on implementing access token based redis clients. Or how can I override the default way redis handles connections to use a username/password that is resolved asyncronously after the client has been created? It would be good if these overrides could be added to the constructor so that developers can work with access tokens without having to hack around it like I'm trying to do.
Thanks.
I attempted to override the connect method by fetching the password before passing it to the original connect. But the issue here is that it doesn't work if the getPassword() function is a promise. It also looks like it under the hood is doing more things than connecting and hence this wouldn't solve the main issue I'm having.
export function getRedisClient(): Redis {
const c = createRedisInstance();
const _clientConnect = c.connect;
const connect = async (callback?: Callback<void>) => {
const password = await getPassword(); // having await here does not work but writing the password directly does strangly.
const username = env.REDIS_USERNAME;
debugInfo(tag, `[connect override] ${username} ${password}`);
c.options.username = username;
c.options.password = password;
await _clientConnect.call(c, callback);
};
c.connect = connect;
return c;
}
Suggestion:
Change the password RedisOption to allow it to be either a string or a Promise
/**
* If set, client will send AUTH command with the value of this option when connected.
*/
password?: string | Promise<string>
See also #1738