OAuth (and others) re-authenticating on each request

Summary

Using the OAuth template, I noticed that on every request, I was seeing this in the logs

level=INFO message=OAuth authorization attempt was successful.

Steps to reproduce

Use the template for any tap that involves setup (doing the token dance and see it happen)

What is the current bug behavior?

Every time we prepare a request we're instantiating the authenticator.

# client.py

    @property
    def authenticator(self) -> MySourceNameAuthenticator:
        """Return a new authenticator object."""
        return MySourceNameAuthenticator.create_for_stream(self)

And in prepare_request:

    def prepare_request(...) :

      ...

        authenticator = self.authenticator
        if authenticator:
            headers.update(authenticator.auth_headers or {})

What is the expected correct behavior?

The authenticator should be instantiated once for the entire client.

Possible fixes

The shortest path to a fix is to make the authenticator a singleton, i.e.:

class MyStream(RESTStream):
    """MyStream stream class."""

    _authenticator = None

    @property
    def authenticator(self) -> MyStreamAuthenticator:
        """Return a new authenticator object."""
        if not self._authenticator:
            self._authenticator = MyStreamAuthenticator.create_for_stream(self)

        return self._authenticator

Luckily the user can do this for their own streams, but the cookiecutter template should be fixed.

Edited by Borna Almasi