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

# Connect a user's account

> Run OAuth once, per end user, and let the Engine keep the tokens working.

When your product acts on behalf of individual users, each one needs their own provider connection. The Engine owns the consent round trip, encrypted token storage, and refresh. Tokens are never returned to your application.

There are two separate things here, easy to conflate:

* **The app credentials** — the provider's `client_id` and `client_secret`. Your own pair lives in your bucket; a Fused Managed App's client secret stays on the broker.
* **A user connection** — one person's grant against that registration. Many per registration.

## Choose a provider application

Use a [Managed service](/docs/workspace/use-managed-service) where Fused offers the exact service and auth scheme, or register your own provider app using the steps below. Both choices store user connections in your Engine and use its existing refresh coordination. Managed auth still requires user consent; it does not expose Fused's application secret to your bucket.

For managed CLI consent, pass `--auth-ref '${fused.bucket.auth.<service>.<auth-name>}'`. SDK and MCP connections use the reference from their applied app config. The [Managed service guide](/docs/workspace/use-managed-service#connect-a-user) covers enrollment, callback requirements, and the complete command.

## Store the OAuth app credentials

Register the app with the provider, then store its complete client pair in the
bucket. This is an immediate admin action. It does not wait for a workspace
plan or apply.

```bash theme={null}
fused-cli secret set jira --bucket prod-credentials
```

The CLI asks you to choose a supported authentication method, then securely prompts for its fields. To automate the same OAuth write, select the exact scheme and provide the complete pair through stdin:

```bash theme={null}
printf '%s' 'client_id=abc;client_secret=xyz' \
  | fused-cli secret set jira \
      --bucket prod-credentials \
      --type oauth \
      --auth-name JiraOAuth \
      --no-input \
      --value-stdin
```

The stdin value must contain exactly `client_id` and `client_secret`. The CLI
rejects blank, partial, or extra fields, including `redirect_uri`. Use `--type
oidc` for an OIDC scheme.

<Note>
  Configure the provider with
  `<engine.public_url>/workspace/connect/callback`. The Engine derives this
  callback from its validated canonical public URL and pins it to the consent
  session. You do not send it as credential input.
</Note>

### `secret set` flags

| Flag            | What it does                                                        | Example                                                                                                                              |
| --------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `--bucket`      | Bucket that owns the credentials; omit it to use the default bucket | `fused-cli secret set jira --bucket prod-credentials --type oauth --auth-name JiraOAuth`                                             |
| `--no-input`    | Disables prompts for automation                                     | `fused-cli secret set jira --type oauth --auth-name JiraOAuth --no-input --value-stdin`                                              |
| `--value-stdin` | Selects stdin as the complete client-pair source                    | `printf '%s' 'client_id=…;client_secret=…' \| fused-cli secret set jira --type oauth --auth-name JiraOAuth --no-input --value-stdin` |
| `--type`        | Selects `oauth` or `oidc`                                           | `fused-cli secret set jira --type oauth --auth-name JiraOAuth`                                                                       |
| `--auth-name`   | Selects the exact Registry auth scheme                              | `fused-cli secret set jira --type oauth --auth-name JiraOAuth`                                                                       |

The retained `--interactive` flag explicitly requires the normal terminal prompts. Omit it for ordinary terminal use.

The pair is atomic. Supply both values when creating or rotating it. Secret
values cannot be read back. Use `fused-cli secret list --bucket
prod-credentials` to inspect secret metadata, or `fused-cli bucket services
prod-credentials` to see application-credential counts by service.

## Reuse an OAuth app for another service

Compatible services can share one client pair without copying it. Store the
pair under the source service, then reference that complete credential family
from the target service in the SDK or MCP app configuration. Provider
credentials and references never belong in `.fused/workspace.yaml`:

```yaml theme={null}
apiVersion: fused/v1
kind: sdk
name: sheets-reader
version: 1.0.0
language: typescript
bucket: default
services:
  google-sheets:
    version: v4
    operations:
      - spreadsheets.get
    auth:
      type: oauth
      name: oauth2
      ref: "${bucket.auth.gmail.oauth2}"
    connect:
      scopes:
        - https://www.googleapis.com/auth/spreadsheets.readonly
```

For a generated SDK runtime, pin the reference by planning and applying the app
configuration:

```bash theme={null}
fused-cli sdk plan -f .fused/sdks/sheets-reader.yaml
fused-cli sdk apply -f .fused/sdks/sheets-reader.yaml
```

For a standalone CLI connection, pass the same reference explicitly. The
command does not load an SDK or MCP app and cannot infer the mapping from app
identity:

```bash theme={null}
fused-cli workspace service connect google-sheets \
  --bucket default \
  --user-ref user_123 \
  --type oauth \
  --auth-name oauth2 \
  --auth-ref '${bucket.auth.gmail.oauth2}'
```

The reference always uses the app's selected bucket. `gmail.oauth2` selects
the source service and its exact auth scheme. The destination declares its own
exact scheme, and the Engine verifies that both credential families are
compatible. The source service must be workspace-enabled and hold credentials
directly, but it does not need to appear in the app's `services` selection.
References cannot chain through another reference.

Consent, callback exchange, managed refresh, SDK readiness, and MCP readiness
all resolve the same reference. Rotating the source pair therefore reaches the
target without copying credentials or applying the workspace again. Publish a
new immutable app version when its reference changes. Each
service still stores its connected users' access, refresh, and ID tokens
separately from the shared app credentials.

## Connect a user

```bash theme={null}
fused-cli workspace service connect jira \
  --bucket prod-credentials \
  --user-ref user_123 \
  --scope read:jira-work \
  --scope write:jira-work
```

Omit `--scope` to request the service's declared scope catalogue. OIDC subsets must include `openid`.

### `workspace service connect` flags

| Flag               | What it does                                                 | Example                                                                                                                                                      |
| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--bucket`         | Bucket holding or referencing the app credentials (required) | `fused-cli workspace service connect jira --bucket prod --user-ref user_123`                                                                                 |
| `--user-ref`       | Stable end-user reference (required)                         | `fused-cli workspace service connect jira --bucket prod --user-ref user_123`                                                                                 |
| `--scope`          | Requests one scope; repeatable                               | `fused-cli workspace service connect jira --bucket prod --user-ref user_123 --scope read:jira-work`                                                          |
| `--auth-ref`       | Selects a local source registration or a Fused Managed App   | `fused-cli workspace service connect slack --bucket prod --user-ref user_123 --type oauth --auth-name oauth2 --auth-ref '${fused.bucket.auth.slack.oauth2}'` |
| `--resource-input` | Tenant input as `key=value`; repeatable                      | `fused-cli workspace service connect jira --bucket prod --user-ref user_123 --resource-input site=acme`                                                      |

The command has no SDK or MCP identity selector. Generated runtimes use the
`auth.ref` in their immutable app configuration; standalone initialization
resolves reuse only from the explicit `--auth-ref` shown above and sends no app
ID. Only a generated SDK attaches its embedded immutable app ID as provenance;
the connected-user grant remains owned by the bucket.

That `--user-ref` is the same value your application later sends as `endUserRef`, or an agent sends as `X-Fused-End-User-Ref`. Keep it stable.

## Refresh happens without you

Nobody refreshes a token through the CLI or the SDK. The Engine refreshes eligible connections at startup and hourly, scheduling from whichever expires first.

An expired access token is not a reconnect — the Engine can rotate it while the refresh token is still good. A connection becomes `reconnect_required` only when refresh material is missing, expired, revoked, or rejected. Then you run the same connect flow again for that bucket, service, auth name, and user reference.

<Warning>
  Never treat an unexpected provider 401 or 403 as permission to replay a mutation.
</Warning>

## One user, several tenants

A single OAuth token can front several provider sites, shops, or accounts. The Engine discovers them and picks a default when there is exactly one.

```bash theme={null}
fused-cli workspace connection resources list <connection-id> --json
fused-cli workspace connection resources set-default <connection-id> <resource-id>
fused-cli workspace connection resources rediscover <connection-id>
```

With several resources and no default, a call must pass an explicit `X-Fused-Resource-ID` or `resourceId`, or it fails with a structured ambiguity error. `rediscover` drops resources the provider no longer returns; if the default disappears, selection falls back to the ordinary rules rather than routing to a stale tenant.

## Who has connected

```bash theme={null}
fused-cli bucket connections prod-credentials --service jira
fused-cli bucket connections prod-credentials --service jira,github@v3
fused-cli bucket connections prod-credentials --service jira --service github@v3
fused-cli bucket connections prod-credentials --user user_123
```

`--service` accepts comma-separated values or repeated flags. Use `<service>@<version>` to match only one immutable service version; a service without a version matches all of its versions. The resulting union is paginated by Engine. This lists every matching end user who has connected through the bucket, and whether their token is healthy. Do not confuse it with `workspace connection resources`, which is about one already-connected user's reachable tenants.

<Card title="Share the bucket" icon="users" href="/docs/bucket/share-a-bucket">
  Let other teams select this bucket without handing them its contents.
</Card>
