#7474·nango

github-app-oauth: userCredentials lost after successful installation

Author: ryannle1Created Sep 9, 2026Updated Sep 9, 2026

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

  1. 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.
  2. Create a github-app-oauth integration with the App ID, public link, signing key, OAuth client ID and client secret.
  3. Initiate Nango Connect from the product using a server-created session restricted to this integration and private user/workspace tags.
  4. Install and authorize the App on one disposable private repository, completing GitHub reauthentication.
  5. After Nango reports success, call GET /connections/{id}?provider_config_key=github-app-oauth&refresh_token=true with environment:connections:read_credentials scope.
  6. Observe the same missing user credential on subsequent reads. A single additional read with force_refresh=true changes 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.

json
{
  "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 connectionConfig object.
  • The GitHub post-connection hook saves the OAuth2 credential under userCredentials after reading /user.
  • Installation completion passes its configuration to upsertConnection, whose existing-row update replaces connection_config instead 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?