airbytehq / airbytehq/airbyte

[source-salesloft] OAuth refresh fails in v1.5.2 due to SingleUseOauth2Authenticator attribute error

Abierto
#84,297 2 comentarios 0 reacciones 0 asignados Ver en GitHub
area/connectors autoteam community connectors/source/salesloft needs-triage team/extensibility team/use type/bug
Lenguaje dominante
Python
Estrellas
22.1k
Forks
5.3k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

### Connector Name

source-salesloft

### Connector Version

1.5.2

### What step the error happened?

Other

### Relevant information

## What step did the error happen?

During source connection check and during sync after the OAuth access token expires.

## Summary

The Salesloft Marketplace connector works while the configured OAuth access token is still valid, but fails as soon as Airbyte attempts to refresh the token.

The refresh path raises:

```text
AttributeError: 'SingleUseOauth2Authenticator' object has no attribute '_token_refresh_endpoint'
Did you mean: 'token_refresh_endpoint'?
```

This prevents long-running Salesloft syncs from continuing beyond the access-token lifetime.

## Reproduction

1. Configure `source-salesloft:1.5.2` using valid OAuth credentials:
- access token
- refresh token
- client ID
- client secret
- token expiry date
2. Set `token_expiry_date` a few minutes in the future.
3. Run `Test source` before expiry.
4. The connection succeeds.
5. Wait until `token_expiry_date` passes.
6. Run `Test source` again without changing credentials.
7. The connector fails while attempting to refresh the token.

## Observed error

```text
File ".../abstract_oauth.py", line 118, in _get_refresh_access_token_response
response = requests.request(
method="POST",
url=self.get_token_refresh_endpoint(),
data=self.build_refresh_request_body()
)

File ".../oauth.py", line 56, in get_token_refresh_endpoint
return self._token_refresh_endpoint

AttributeError:
'SingleUseOauth2Authenticator' object has no attribute
'_token_refresh_endpoint'.
Did you mean: 'token_refresh_endpoint'?
```

The exception is then surfaced as:

```text
Exception: Error while refreshing access token:
'SingleUseOauth2Authenticator' object has no attribute '_token_refresh_endpoint'
```

## Expected behavior

When the access token expires, the connector should POST the refresh token to:

```text
https://accounts.salesloft.com/oauth/token
```

and continue using the refreshed access token.

## Additional evidence

I reproduced this both:

- during a long-running sync, after substantial data had already been successfully read from Salesloft
- during a source connection test by deliberately setting `token_expiry_date` shortly in the future

This confirms that initial OAuth authentication works and that the failure occurs specifically in the refresh path.

## Possible cause

The declarative manifest uses:

```yaml
type: CustomAuthenticator
class_name: source_declarative_manifest.components.SingleUseOauth2Authenticator
token_refresh_endpoint: https://accounts.salesloft.com/oauth/token
```

but the CDK method `get_token_refresh_endpoint()` attempts to read:

```python
self._token_refresh_endpoint
```

while the authenticator appears to expose/use `token_refresh_endpoint`.

## Workaround / confirmation

I copied the connector manifest into Connector Builder and replaced the custom authenticator with Airbyte's native `OAuthAuthenticator`.

With the native authenticator, the same forced-expiry test succeeds after token expiry, including repeated `Retest saved source` checks.

This strongly suggests the Salesloft API credentials and refresh endpoint are valid and that the failure is specific to the Marketplace connector's custom authenticator implementation.

### Relevant log output

```shell
## Relevant log output

### Connection check failure after token expiry

2026-08-12 08:16:37 error Encountered an error trying to connect to stream users. Error:

File "/usr/local/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py", line 118, in _get_refresh_access_token_response
response = requests.request(
method="POST",
url=self.get_token_refresh_endpoint(),
data=self.build_refresh_request_body()
)

File "/usr/local/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py", line 56, in get_token_refresh_endpoint
return self._token_refresh_endpoint

AttributeError: 'SingleUseOauth2Authenticator' object has no attribute '_token_refresh_endpoint'. Did you mean: 'token_refresh_endpoint'?

The exception then propagates through the OAuth refresh path:

File "/usr/local/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py", line 231, in get_access_token
new_access_token, access_token_expires_in, new_refresh_token = self.refresh_access_token()

File "/usr/local/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py", line 246, in refresh_access_token
response_json = self._get_refresh_access_token_response()

File "/usr/local/lib/python3.10/site-packages/airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py", line 142, in _get_refresh_access_token_response
raise Exception(f"Error while refreshing access token: {e}") from e

Exception: Error while refreshing access token: 'SingleUseOauth2Authenticator' object has no attribute '_token_refresh_endpoint'

2026-08-12 08:16:37 error Check failed

This confirms that the failure occurs specifically when the connector enters the OAuth refresh path. :contentReference[oaicite:0]{index=0} :contentReference[oaicite:1]{index=1}

### Evidence that the connector works normally before refresh is required

During the earlier sync, streams were successfully reading records before the token refresh failure occurred:

2026-08-11 16:14:15 info Read 10 records from person_stages stream
2026-08-11 16:14:15 info Finished syncing person_stages

2026-08-11 16:14:15 info Read 27 records from phone_number_assignments stream
2026-08-11 16:14:15 info Finished syncing phone_number_assignments

2026-08-11 16:14:15 info Syncing stream: steps
2026-08-11 16:14:15 info Read 0 records from steps stream

This shows that initial authentication and API requests were functioning before token refresh was triggered. :contentReference[oaicite:2]{index=2}
```

### Contribute

- [ ] Yes, I want to contribute

---
**Internal Tracking:** https://github.com/airbytehq/oncall/issues/13289

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.