> ## Documentation Index
> Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth2 token lifecycle and required scopes

Use this reference to understand how watsonx Orchestrate stores and refreshes OAuth2 access tokens for tool connections. OAuth scopes are required for specific catalog tools, and what to do when a tool stops working after its initial token expires.

## How watsonx Orchestrate manages OAuth2 tokens

When a user authorizes an OAuth2 connection through the watsonx Orchestrate UI, the platform performs the authorization code exchange and stores two tokens on behalf of that user:

| Token           | Purpose                                                                                  | Lifetime                                                |
| --------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `access_token`  | Passed directly to the downstream tool on every invocation                               | Short-lived (typically 1–60 minutes, provider-specific) |
| `refresh_token` | Used by Orchestrate to silently obtain a new `access_token` when the current one expires | Long-lived (days to months, or until revoked)           |

On each tool invocation, watsonx Orchestrate checks whether the stored `access_token` is still valid. If it is expired, watsonx Orchestrate automatically calls the provider's token endpoint with the stored `refresh_token` to obtain a new `access_token`, then retries the tool call, without requiring to reauthorize.

<Note>
  OAuth-based connections currently work when the user interacts with the agent through the watsonx Orchestrate UI (not embedded web chat). See [Why use connections](/connections/overview) for a full compatibility matrix.
</Note>

## Refresh tokens are issued when `offline_access` is requested

The most common reason that a tool works initially but stops working after the first token expiry is a missing refresh token. OAuth2 providers issue a `refresh_token` when the authorization request explicitly includes the `offline_access` scope (or an equivalent provider-specific scope). If `offline_access` is omitted, the provider issues an `access_token` with no way to renew it. When that token expires, every subsequent tool call fails with an authentication error.

Make sure the `offline_access` scope is included in your connection's scope list at the time of initial authorization. Adding it after the fact requires the user to reauthorize the connection from the beginning. You cannot back-fill a refresh token.

## Required scopes by catalog tool

The following table lists the minimum scopes required for common catalog integrations. Scopes marked `required for refresh` must be included or the connection will stop working after the first `access_token` expiry.

| Tool        | Required scopes                                              | Notes                                                                                                                                                                        |
| ----------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Jira        | `read:jira-work`, `write:jira-work`, `offline_access`        | `offline_access` is required for refresh. Atlassian doesn't issue a refresh token without it.                                                                                |
| Salesforce  | `api`, `refresh_token` or `offline_access`                   | Salesforce uses `refresh_token` as the scope name. Both `refresh_token` and `offline_access` are accepted, include at least one.                                             |
| GitHub      | `repo`, `offline_access` *(if supported by your GitHub App)* | GitHub does not support `offline_access` on the standard OAuth App flow. Use a GitHub App with fine-grained tokens and a long expiry, or reauthorize when the token expires. |
| Other tools | Consult the provider's OAuth2 documentation                  | Look for a scope named `offline_access`, `offline`, or `refresh_token`.                                                                                                      |

<Warning>
  Jira refresh tokens require `offline_access`

  Atlassian's OAuth 2.0 (3LO) implementation does not issue a refresh token unless `offline_access` is explicitly included in the scope list at authorization time. If this scope is missing, the connection will appear good until the initial `access_token` expires (after one hour), at which point every Jira tool call will return an authentication error.

  Make sure the `offline_access` scope in the [Atlassian Developer Console](https://developer.atlassian.com/console/myapps/) is enabled, and pass it in the `--scope` flag when you set credentials:

  ```bash BASH theme={null}
  orchestrate connections set-credentials -a jira \
    --env draft \
    --client-id '<client_id>' \
    --client-secret '<client_secret>' \
    --authorization-url 'https://auth.atlassian.com/authorize' \
    --token-url 'https://auth.atlassian.com/oauth/token' \
    --scope 'read:jira-work write:jira-work offline_access'
  ```
</Warning>

## Setting scopes when configuring an OAuth connection

Scopes are set as part of the `set-credentials` step for any auth-code or password flow connection. Pass a space-separated list of scope values to the `--scope` flag:

```bash BASH theme={null}
orchestrate connections set-credentials -a <app_id> \
  --env draft \
  --client-id '<client_id>' \
  --client-secret '<client_secret>' \
  --authorization-url 'https://provider.example.com/oauth/authorize' \
  --token-url 'https://provider.example.com/oauth/token' \
  --scope '<scope1> <scope2> offline_access'
```

When you import from a YAML file, scopes are stored as part of the connection credentials, not the YAML spec itself. The YAML file defines the connection structure. You still run `set-credentials` separately to supply the scope list and other sensitive values.

<Note>
  There is no dedicated "Scopes" field in the Connections Management UI. Scopes are configured exclusively through the CLI `set-credentials` command. If you need to change the scope list for an existing connection, rerun `set-credentials` with the updated `--scope` value and then have each affected user reauthorize the connection.
</Note>

## What happens when a token expires

| Situation                                     | Outcome                                                                                                          |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `access_token` expires, refresh token present | watsonx Orchestrate silently renews the `access_token` and retries the tool call. The user sees no interruption. |
| `access_token` expires, no refresh token      | The tool call fails. The user sees an authentication error in the chat UI.                                       |
| `refresh_token` itself expires or is revoked  | watsonx Orchestrate cannot renew the `access_token`. The tool call fails with an authentication error.           |
| Connection reauthorized with incorrect scopes | A new access token is issued but without `offline_access`, so the cycle repeats after the next expiry.           |

## Troubleshooting: tool stops working after initial authorization

If a tool that was working correctly starts returning authentication errors, follow these steps:

<Steps>
  <Step title="Check whether a refresh token was issued">
    The most common root cause is a missing `offline_access` scope on the original authorization. Review the scope list in your connection credentials:

    ```bash BASH theme={null}
    orchestrate connections list
    ```

    Inspect the connection's configured scopes. If `offline_access` (or the provider-equivalent) is absent, proceed to step 2.
  </Step>

  <Step title="Update the scope list">
    Rerun `set-credentials` with the corrected scope list, including `offline_access`:

    ```bash BASH theme={null}
    orchestrate connections set-credentials -a <app_id> \
      --env draft \
      --client-id '<client_id>' \
      --client-secret '<client_secret>' \
      --authorization-url 'https://provider.example.com/oauth/authorize' \
      --token-url 'https://provider.example.com/oauth/token' \
      --scope '<existing_scopes> offline_access'
    ```
  </Step>

  <Step title="Re-authorize the connection">
    Updating the scope list alone is not sufficient, the provider issues a refresh token during the authorization flow. Each user who holds the connection must reauthorize it:

    1. From the main menu in the watsonx Orchestrate UI, go to Manage > Security > Connections
    2. Locate the affected connection and click the overflow menu icon and select Edit connection.
    3. Click Connect now.
    4. Complete the OAuth consent screen, ensuring the updated scopes are shown.

    After re-authorization, watsonx Orchestrate stores the new `access_token` and if `offline_access` was included, the `refresh_token`. Subsequent token renewals will happen silently.
  </Step>

  <Step title="Verify the fix">
    Run a test invocation of the affected tool from the agent chat UI. If the call succeeds, the refresh token is in place. If it fails again, check that the OAuth app in the provider's developer console has `offline_access` enabled as an allowed scope.
  </Step>
</Steps>

## Token storage and security

watsonx Orchestrate stores access tokens and refresh tokens encrypted at rest, scoped to the individual user and connection. Tokens are never shown in logs, the CLI output, or the UI. They are decrypted in memory at the moment that a tool call is dispatched to the downstream service.

For team connections, the builder's credentials (including the refresh token) are shared across all users of the agent. For member connections, each user holds their own token pair and must authorize the connection individually.

## Related pages

* [Why use connections](/connections/overview)
* [Creating connections](/connections/build_connections)
* [Managing connections](/connections/managing_connections)
