auth0/node-auth0

AuthenticationClient should support token caching across calls to the same instance

dursin opened this issue · 1 comments

Checklist

  • I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Describe the problem you'd like to have solved

We use M2M tokens to communicate across our microservices, using client credentials grant to generate a token. In the SDK v3, the ManagementClient supported a tokenProvider.enableCache option so that subsequent calls to getAccessToken would reuse the same token as long as it was valid. Now that the functionality to generate these tokens has moved to the AuthenticationClient, I want the same caching mechanism to be available when calling authenticationClient.oauth.clientCredentialsGrant.

Describe the ideal solution

Either cache these tokens by default or the constructor for the AuthenticationClient should support an option to cache these tokens across calls to the same instance.

Alternatives and current workarounds

The current workaround is to cache the token manually, and on each request to a wrapping "getAccessToken" call in our code, check to see if the token is present and not expired before doing a fresh grant. this is boilerplate code I don't want to add to each app that generates a token. Something like this module does it but is not what I want across all my apps

import { AuthenticationClient } from "auth0";

export interface TokenProviderOptions {
    audience: string;
    clientId: string;
    clientSecret: string;
    domain: string;
}

class TokenProvider {
    private authenticationClient: AuthenticationClient;
    private audience: string;
    private accessToken: string | undefined;
    /* Time in ms at which the cached token expires */
    private accessTokenExpiresAt: number;
    private EXPIRATION_THRESHOLD: number = 1000 * 60; // one minute

    public constructor(options: TokenProviderOptions) {
        const { audience, clientId, clientSecret, domain } = options;
        this.audience = audience;
        this.accessToken = undefined;
        this.accessTokenExpiresAt = 0;
        this.authenticationClient = new AuthenticationClient({
            domain,
            clientId,
            clientSecret
        });
    }

    public async getAccessToken(): Promise<string> {
        const timeUntilExpiration = this.accessTokenExpiresAt - Date.now();
        if (!this.accessToken || timeUntilExpiration < 0 || timeUntilExpiration < this.EXPIRATION_THRESHOLD) {
            const token = await this.authenticationClient.oauth.clientCredentialsGrant({ audience: this.audience });
            this.accessToken = token.data.access_token;
            this.accessTokenExpiresAt = token.data.expires_in * 1000 + Date.now();
        }
        return this.accessToken;
    }
}

export default TokenProvider;

Additional context

No response

Thanks for reaching out.

The functionality you were relying on was never something that should have been the responsibility of the Management SDK. The same goes for the Authentication SDK, it's not its responsibility to store the tokens, that should be the responsibility of your own application.

This is in line with our other, comparable SDKs for other languages such as Auth0.NET, Auth0-Java, Auth0-php and Ruby-Auth0, so the removal of that behavior in v4 is intentional.

The code you have seems fine and completely expected. If you believe this is too much boilerplate to add to all microservices, i assume there are always ways to avoid duplicating the same code everywhere by the means of an internal npm package or anything you prefer.

To add a bit more context on why we believe this shouldnt be part of this SDK is the fact that caching the token is complicated. For example, you need to consider audience, scope, or any parameter that you need to consider as identifier for the token in the cache as it should result in not reusing existing tokens (you can not reuse the same token for different audiences or scopes, or other parameters). Additionally, the cache is in memory, which may or may not work depending on the nature of your application (think a load balanced web server, where an in-memory cache might be sub-optimal).

Closing, as this works as intended and we currently have no plans to add token storage to the Authentication API side.