github-app-oauth: userCredentials lost after successful installation
Problem
On Nango Cloud, a fresh github-app-oauth connection completes successfully but exposes only an installation token. The expiring GitHub App user credential is absent from connection_config.userCredentials. A consumer that requires the connecting user's current repository authority must reject this connection.
Reproduction
- Configure a GitHub App with Issues and Metadata read-only, selected repositories, user authorization during installation, expiring user authorization tokens, and callback
https://api.nango.dev/oauth/callback. - Create a
github-app-oauthintegration with the App ID, public link, signing key, OAuth client ID and client secret. - Initiate Nango Connect from the product using a server-created session restricted to this integration and private user/workspace tags.
- Install and authorize the App on one disposable private repository, completing GitHub reauthentication.
- After Nango reports success, call
GET /connections/{id}?provider_config_key=github-app-oauth&refresh_token=truewithenvironment:connections:read_credentialsscope. - Observe the same missing user credential on subsequent reads. A single additional read with
force_refresh=truechanges the installation-token fingerprint but does not add a user credential.
Observed response shape
No credential values, connection IDs or customer information are included here.
{
"provider": "github-app-oauth",
"errors": [],
"credentials": {
"type": "APP",
"access_token": "REDACTED",
"expires_at": "REDACTED",
"jwtToken": "REDACTED",
"raw": {
"token": "REDACTED",
"expires_at": "REDACTED",
"permissions": {"issues": "read", "metadata": "read"},
"repository_selection": "selected"
}
},
"connection_config": {
"appPublicLink": "REDACTED",
"installation_id": "REDACTED",
"jwtToken": "REDACTED"
}
}Cloud log sequence
Observed September 9, 2026, UTC. Both authentication operations were marked successful.
| Time | Event |
|---|---|
| 17:17:30.478 | Token response received |
| 17:17:30.512 | OAuth connection successful |
| 17:17:30.526 | Post-connection operation started |
| 17:17:30.759 | Post-connection-creation script succeeded |
| 17:17:30.816 | App connection approved and credentials saved |
At 17:36 UTC, the user credential remained absent before and after the forced refresh. The consumer’s server-side verification refused the connection; no provider proxy request or source import occurred.
Source investigation — likely overwrite, not a confirmed Cloud build diagnosis
Public source examined at 752cd127dfced933954a34c1cdc357570f95844c; the deployed Cloud revision is unknown.
- The OAuth callback launches the post-connection hook without awaiting it, then finishes the installation using the earlier
connectionConfigobject. - The GitHub post-connection hook saves the OAuth2 credential under
userCredentialsafter reading/user. - Installation completion passes its configuration to
upsertConnection, whose existing-row update replacesconnection_configinstead of merging the newly stored hook fields.
The observed hook-success-before-installation-save ordering is consistent with overwriting userCredentials and handle. The public response formatter passes through the configuration, so serialization does not explain the missing field in the examined revision.
Expected: preserve the current authorizing user's credential through installation completion and reconnect, independently of callback timing, while retaining the installation credential. A fix should cover the hook finishing both before and after the installation write, and repeated user-token refreshes.
This initial-authorization failure precedes the repeated-refresh scenario in #6136; this report does not claim to reproduce that issue.
Can you confirm whether this overwrite exists in Cloud and provide a supported fix or connection flow that reliably preserves the expiring user credential?
Source: NangoHQ/nango