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

# Generic OAuth

The Generic OAuth connector provides a pure OAuth 2.0 integration for upstream authorization servers. It speaks OAuth only -- it does not consume an `id_token` or call a userinfo endpoint. The OAuth connector provides flexibility to connect services like GitHub, Atlassian, and other platforms that support OAuth but not OpenID Connect..

> [!NOTE]
>
> **Console terminology:** In the Maverics Console, this section is called
> **Identity Fabric**. The YAML configuration uses the `connectors` key to define
> identity provider integrations.

## Overview

The Generic OAuth connector targets authorization servers that expose OAuth 2.0 endpoints. It supports two configuration styles -- discovery via a `wellKnownURL`, or manually specified `authorizeURL` and `tokenURL` endpoints -- and a non-standard "no client authentication" mode for federation flows where the upstream authenticates the request via a subject token instead of client credentials.

The connector can also obtain or assert its own client identity instead of using a pre-provisioned one, through [Dynamic Client Registration](#dynamic-client-registration) or a [Client ID Metadata Document](#client-id-metadata-document). See [Client Authentication Modes](#client-authentication-modes) for how the options compare.

The `wellKnownURL` field accepts either an [OAuth Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) document or an [OIDC discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) document (which is a superset of the OAuth metadata format). Either way, the connector reads only the OAuth endpoints from the discovery document -- it does not perform OIDC end-user authentication.

For interactive end-user login against a full OpenID Connect IdP, use the [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) connector instead.

## Use Cases

* **[Token brokering](/reference/orchestrator/experimental/token-brokering) against OAuth-only authorization servers** -- Exchange Orchestrator-issued tokens for upstream tokens (RFC 8693 token exchange) against services like Databricks account-wide federation or GCP Workload Identity Federation, where the upstream exposes OAuth but no `id_token` and no userinfo endpoint.
* **Machine-to-machine outbound calls** -- Authorize outbound calls from the Orchestrator where the upstream authenticates the request via a subject token rather than client credentials.
* **OAuth-only authorization servers** -- Integrate with services like GitHub or Atlassian that provide OAuth 2.0 authorization but not full OIDC, when you need access tokens for API access rather than user identity.
* **Federation without a pre-provisioned credential** -- Connect to an authorization server you cannot register a client with ahead of time. The Orchestrator either registers itself on startup ([Dynamic Client Registration](#dynamic-client-registration)) or identifies itself by a URL it publishes ([Client ID Metadata Document](#client-id-metadata-document)), so no client ID or secret has to be issued and rotated by hand.

## Setup

**Console UI**

To create a Generic OAuth connector in the Maverics Console:

1. Navigate to **Identity Fabric** in the Console sidebar.
2. Click **Create** and select **Generic OAuth**.
3. Enter a **Name** for the connector -- this is the friendly name that identifies your OAuth integration.
4. Provide endpoints either by:

   * Entering the **Well Known URL** -- either an OAuth Authorization Server Metadata URL (RFC 8414) or an OIDC discovery URL; **or**
   * Entering the **Authorization URL** and **Token URL** manually.

   These two approaches are mutually exclusive -- provide one or the other, not both.
5. Enter the **Client ID** issued by the upstream authorization server. Leave this empty if you plan to use CIMD or DCR in step 9.
6. Enter the **Client Secret** associated with the client ID. Use the show/hide toggle to verify the value. Leave this empty if you plan to use CIMD or DCR in step 9.
7. Add one or more **Redirect URLs** -- the URL(s) where the Orchestrator's OAuth handler is served. At least one entry is required.
8. Optionally enable **Disable Client Authentication** if the upstream authorization server authenticates the request via the subject token alone (for example, Databricks account-wide federation). See [Disable Client Authentication](#disable-client-authentication) below.
9. Optionally configure a credential-less mode in the **CIMD / DCR** section at the bottom of the drawer. Leave **Client ID** and **Client Secret** empty to use either one:

   * For [Client ID Metadata Document](#client-id-metadata-document) mode, enter the **Client ID Metadata Document (CIMD) Metadata URL**. This is the HTTPS URL the Orchestrator serves the document at, and the value it presents as its client ID.
   * For [Dynamic Client Registration](#dynamic-client-registration), fill in the **Dynamic Client Registration (DCR)** sub-section: **Client Name** is the display name the authorization server records, and **Token Endpoint Authentication Method** is the authentication method to request.

   CIMD and DCR are mutually exclusive -- configure one or the other, not both.
10. Click **Save**.

> [!TIP]
>
> If your upstream is a full OpenID Connect provider and you need identity claims and end-user session handling out of the box (i.e., `id_token` and userinfo), use the [Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc) connector instead.

**Configuration**

The OAuth connector supports two configuration approaches. Use `wellKnownURL` when
the authorization server publishes a discovery document (either OAuth Authorization
Server Metadata or OIDC discovery), or manually specify the `authorizeURL` and
`tokenURL` endpoints. These two options are mutually exclusive.

**Option 1: Using a well-known discovery URL**

```yaml maverics.yaml theme={null}
connectors:
  - name: databricks
    type: oauth
    clientID: "{{ env.DATABRICKS_CLIENT_ID }}"
    clientSecret: <vault.databricks_client_secret>
    wellKnownURL: https://accounts.cloud.databricks.com/.well-known/oauth-authorization-server
    loginRedirect:
      urls:
        - https://app.example.com/databricks/oauth
```

**Option 2: Manually specifying authorize and token URLs**

```yaml maverics.yaml theme={null}
connectors:
  - name: github
    type: oauth
    clientID: "{{ env.GITHUB_CLIENT_ID }}"
    clientSecret: <vault.github_client_secret>
    authorizeURL: https://github.com/login/oauth/authorize
    tokenURL: https://github.com/login/oauth/access_token
    loginRedirect:
      urls:
        - https://app.example.com/github/oauth
    scopes: repo
```

**Option 3: Registering the client dynamically**

```yaml maverics.yaml theme={null}
connectors:
  - name: partner-oauth
    type: oauth
    wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
    loginRedirect:
      urls:
        - https://app.example.com/partner/oauth
    # No clientID or clientSecret -- the Orchestrator registers itself on startup.
    dcr:
      clientName: Maverics Orchestrator
```

**Option 4: Identifying the client by a metadata document URL**

```yaml maverics.yaml theme={null}
connectors:
  - name: partner-oauth
    type: oauth
    wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
    loginRedirect:
      urls:
        - https://app.example.com/partner/oauth
    cimd:
      # Served by the Orchestrator at this address, and presented as the client ID.
      url: https://app.example.com/.well-known/oauth-client
```

See [Dynamic Client Registration](#dynamic-client-registration) and [Client ID Metadata Document](#client-id-metadata-document) for how each mode behaves.

## Configuration Reference

| Key | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Friendly name of the connector, referenced in app policies. |
| `type` | string | Yes | Must be `oauth`. |
| `wellKnownURL` | string | Conditional | Discovery document URL -- either OAuth Authorization Server Metadata (RFC 8414) or OIDC discovery. The connector reads only the OAuth endpoints. Provide this **or** `authorizeURL` + `tokenURL`, not both. |
| `authorizeURL` | string | Conditional | OAuth 2.0 authorization endpoint. Required only when `wellKnownURL` is omitted. Mutually exclusive with `wellKnownURL`. |
| `tokenURL` | string | Conditional | OAuth 2.0 token endpoint. Required only when `wellKnownURL` is omitted. Mutually exclusive with `wellKnownURL`. |
| `clientID` | string | Conditional | OAuth 2.0 client ID. Required unless `disableClientAuthentication` is `true`, in which case it is optional (some grants may still require it at runtime). Must be empty when `dcr` or `cimd` is configured. |
| `clientSecret` | string | Conditional | OAuth 2.0 client secret (use secret reference syntax). Required unless `disableClientAuthentication` is `true`, in which case it must be empty. Must be empty when `dcr` or `cimd` is configured. |
| `loginRedirect.urls` | list | Yes | Redirect URL(s) where the Orchestrator's OAuth handler is served. At least one entry is required. |
| `disableClientAuthentication` | boolean | No | When `true`, the Orchestrator does not send `client_secret` in OAuth form bodies. See [Disable Client Authentication](#disable-client-authentication). Defaults to `false`. |
| `scopes` | string | No | Space-separated OAuth scopes to request. |
| `dcr` | object | No | Enables [Dynamic Client Registration](#dynamic-client-registration) (RFC 7591). Requires `wellKnownURL`. Mutually exclusive with `clientID`, `clientSecret`, `disableClientAuthentication`, and `cimd`. |
| `dcr.clientName` | string | No | Display name sent as `client_name` in the registration request. |
| `dcr.tokenEndpointAuthMethod` | string | No | The `token_endpoint_auth_method` to request. When omitted, the authorization server chooses. |
| `cimd` | object | No | Enables [Client ID Metadata Document](#client-id-metadata-document) mode. Mutually exclusive with `clientID`, `clientSecret`, `disableClientAuthentication`, and `dcr`. |
| `cimd.url` | string | Conditional | HTTPS URL the metadata document is served at, and the connector's client ID. Required when `cimd` is set. Must be lowercase, include a path, and omit any query string, fragment, userinfo, or dot-segments. |
| `errorHandling` | object | No | Configures redirect rules applied when any error occurs during callback processing. See [Callback Error Handling](#callback-error-handling) below. |

For the complete field reference including health checks, see [Identity Fabric](/reference/orchestrator/identity-fabric#configuration-reference).

## Client Authentication Modes

The connector authenticates to the upstream authorization server in one of four ways. Choose one -- they are mutually exclusive.

| Mode | Configuration | Client authentication |
| - | - | - |
| Static credentials (default) | `clientID` + `clientSecret` | Sends `client_secret` in the OAuth form body. |
| [Dynamic Client Registration](#dynamic-client-registration) | `dcr` | Uses the credential the authorization server issues at startup. |
| [Client ID Metadata Document](#client-id-metadata-document) | `cimd` | None. The connector is a public client and PKCE protects the code exchange. |
| [No client authentication](#disable-client-authentication) | `disableClientAuthentication: true` | None. The subject token authenticates the request. |

> [!NOTE]
>
> Configuring `dcr` or `cimd` alongside `clientID`, `clientSecret`, `disableClientAuthentication`, or each other is rejected when the configuration loads. Both modes install their own client ID, so a connector configured for two of them would have one silently overwrite the other.

> [!WARNING]
>
> Dynamic Client Registration and Client ID Metadata Document mode require Orchestrator **v2026.08.2** or later. Earlier versions ignore the `dcr` and `cimd` keys.

## Dynamic Client Registration

Dynamic Client Registration ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) lets the Orchestrator create its own OAuth client at the upstream authorization server instead of using credentials you provision by hand. Add a `dcr` block and omit `clientID` and `clientSecret`.

```yaml maverics.yaml theme={null}
connectors:
  - name: partner-oauth
    type: oauth
    wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
    loginRedirect:
      urls:
        - https://app.example.com/partner/oauth
    dcr:
      # Display name the authorization server records for the registered client.
      clientName: Maverics Orchestrator
```

### How registration works

DCR requires `wellKnownURL`. The Orchestrator reads the `registration_endpoint` from the discovery document, so it cannot be used with manually specified `authorizeURL` and `tokenURL` endpoints.

Registration runs once when the connector starts, as part of discovery. The Orchestrator sends a `POST` to the registration endpoint containing:

* `client_name` -- from `dcr.clientName`.
* `token_endpoint_auth_method` -- from `dcr.tokenEndpointAuthMethod`, when set.
* `grant_types` -- `authorization_code`.
* `response_types` -- `code`.
* `redirect_uris` -- the connector's `loginRedirect.urls`.

The Orchestrator accepts an HTTP 200 or 201 response and reads `client_id`, `client_secret`, and `token_endpoint_auth_method` from it. A `client_id` is required -- registration fails without one. If the response sets `token_endpoint_auth_method` to `none` or omits `client_secret`, the connector operates as a public client and sends no client credential on subsequent requests.

> [!WARNING]
>
> Registered credentials are held in memory only. They are not persisted, so **the connector registers a new client every time the Orchestrator restarts**. On an authorization server that retains registrations, this accumulates clients over time. Confirm your server's registration limits and cleanup policy before enabling DCR in production.

> [!NOTE]
>
> When `dcr` is configured, a failure to load the discovery document is fatal -- the connector does not start. Without `dcr`, the same failure is logged and startup continues.

## Client ID Metadata Document

> [!WARNING]
>
> Client ID Metadata Documents are an experimental feature -- see [Experimental Features](/reference/orchestrator/experimental/overview) for important caveats.

Client ID Metadata Document (CIMD) mode, defined in [draft-ietf-oauth-client-id-metadata-document](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/), lets the connector identify itself by an HTTPS URL rather than a registered client ID. The Orchestrator serves a JSON metadata document at that URL and presents the same URL as its client ID in every authorization and token request. Nothing is registered with the authorization server in advance.

A CIMD connector is a public client: PKCE protects the authorization code exchange in place of a client credential.

> [!NOTE]
>
> This section covers the Orchestrator acting as a **CIMD client** toward an upstream authorization server. For the Orchestrator acting as an **authorization server** that accepts CIMD clients, see [Client ID Metadata Documents](/reference/orchestrator/experimental/client-id-metadata-documents).

```yaml maverics.yaml theme={null}
connectors:
  - name: partner-oauth
    type: oauth
    wellKnownURL: https://auth.example.com/.well-known/oauth-authorization-server
    loginRedirect:
      urls:
        - https://app.example.com/partner/oauth
    cimd:
      # Served by the Orchestrator at this address, and presented verbatim as the
      # client ID. Must be lowercase and reachable by the authorization server.
      url: https://app.example.com/.well-known/oauth-client
    # Listing offline_access adds refresh_token to the published grant types.
    scopes: offline_access
```

### The published document

The Orchestrator builds the metadata document from the connector's own configuration -- there are no separate fields to set. The example above publishes:

```json theme={null}
{
  "client_id": "https://app.example.com/.well-known/oauth-client",
  "client_name": "partner-oauth",
  "client_uri": "https://app.example.com",
  "redirect_uris": ["https://app.example.com/partner/oauth"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "scope": "offline_access",
  "token_endpoint_auth_method": "none"
}
```

| Field | Derived from |
| - | - |
| `client_id` | `cimd.url`, verbatim. |
| `client_name` | The connector's `name`. |
| `client_uri` | The scheme and host of `cimd.url`, including a non-default port. Not configurable, so it cannot drift from `client_id` under an authorization server that enforces a same-domain rule between the two. |
| `redirect_uris` | The connector's `loginRedirect.urls`. |
| `grant_types` | `authorization_code`, plus `refresh_token` when `offline_access` is among the requested `scopes`. |
| `response_types` | Always `code`. |
| `scope` | The connector's `scopes`. Omitted when `scopes` is unset. |
| `token_endpoint_auth_method` | Always `none`. |

The document is served with a `Content-Type` of `application/json` and `Cache-Control: max-age=3600`.

> [!NOTE]
>
> The Generic OAuth connector has no `offlineAccess` setting. To publish the `refresh_token` grant, list `offline_access` in `scopes` directly, as in the example above.

### URL requirements

The Orchestrator registers a route from the host and path of `cimd.url`, dropping the scheme, port, and any trailing slash. The Orchestrator must be reachable at that host and path from the authorization server, or the server cannot fetch the document.

`cimd.url` is validated when the configuration loads and must:

* Use the `https` scheme.
* Include a host and a path other than `/`.
* Omit any query string, fragment, or userinfo component.
* Omit dot-segments (`.` and `..`).
* Be **entirely lowercase**, in both host and path. The route is registered lowercased while the published client ID keeps the casing you configure, so a mixed-case URL would return 404 at the very address the document advertises.

### Discovery

If the authorization server's discovery document omits `client_id_metadata_document_supported`, the Orchestrator logs a message and proceeds anyway, since some servers accept CIMD clients without advertising support.

## Disable Client Authentication

Setting `disableClientAuthentication: true` is intended for federation flows where the upstream authorization server authenticates the request via the subject token alone -- for example, Databricks account-wide federation. When enabled:

* `clientSecret` must be empty.
* `clientID` becomes optional, though some grants may still require it at runtime.
* The Orchestrator enforces grant-type-level rules. For instance, the client-credentials and Resource Owner Password Credentials (ROPC) grants are rejected at runtime when client authentication is disabled, because those grants depend on client credentials to authenticate the request.

```yaml maverics.yaml theme={null}
connectors:
  - name: databricks-federation
    type: oauth
    clientID: "{{ env.DATABRICKS_CLIENT_ID }}"
    wellKnownURL: https://accounts.cloud.databricks.com/.well-known/oauth-authorization-server
    loginRedirect:
      urls:
        - https://app.example.com/databricks/oauth
    disableClientAuthentication: true
```

## Callback Error Handling

When an error occurs during the OAuth callback -- whether the authorization server returns an error, the state parameter is invalid, or the token request fails -- the Orchestrator can evaluate configurable rules to redirect the user to a specific URL based on the error.

Rules are evaluated in order -- the first matching rule wins. You can match on the `error` or `error_description` callback parameters using exact or substring matching. A default catch-all rule can be included to handle any unmatched errors.

> [!NOTE]
>
> A `traceID` query parameter is appended to all error redirect URLs automatically. Use this value to look up the corresponding log entries and diagnose why the callback failed.

Rules are defined under `errorHandling.onCallbackError`:

```yaml maverics.yaml theme={null}
connectors:
  - name: github
    type: oauth
    clientID: "{{ env.GITHUB_CLIENT_ID }}"
    clientSecret: <vault.github_client_secret>
    authorizeURL: https://github.com/login/oauth/authorize
    tokenURL: https://github.com/login/oauth/access_token
    loginRedirect:
      urls:
        - https://app.example.com/github/oauth
    errorHandling:
      onCallbackError:
        - contains: "access_denied"
          matchOn: error
          redirectURL: "https://app.example.com/access-denied"
        - equals: server_error
          matchOn: error
          redirectURL: "https://app.example.com/error"
        - default: true
          redirectURL: "https://app.example.com/generic-error"
```

### Rule Reference

Each rule in the `onCallbackError` list supports the following fields:

| Key | Type | Required | Description |
| - | - | - | - |
| `contains` | string | Conditional | Matches when the target field contains this substring. Mutually exclusive with `equals`. Required unless `default` is `true`. |
| `equals` | string | Conditional | Matches when the target field exactly equals this value. Mutually exclusive with `contains`. Required unless `default` is `true`. |
| `matchOn` | string | Conditional | Which callback parameter to match against. Must be `error` or `error_description`. Required unless `default` is `true`. |
| `redirectURL` | string | Yes | The URL to redirect the user to when the rule matches. |
| `default` | boolean | No | When `true`, this rule acts as a catch-all for any error not matched by prior rules. When set, `contains`, `equals`, and `matchOn` must not be defined. Only one default rule is allowed. |

> [!NOTE]
>
> If no rule matches the error and no `default` rule is defined, the Orchestrator falls back to standard error handling behavior.

## Troubleshooting

* **Verify the `authorizeURL` and `tokenURL` are accessible** from the Orchestrator host -- confirm both endpoints respond correctly.
* **If using `wellKnownURL`**, ensure the discovery document URL is correct and returns valid JSON with `authorization_endpoint` and `token_endpoint` fields.
* **Ensure the `loginRedirect` URLs match exactly** what is registered with the upstream authorization server.
* **Check that the client secret reference resolves correctly** via your secret provider -- unless `disableClientAuthentication` is `true`, in which case `clientSecret` must be empty.
* **If `disableClientAuthentication` is `true`**, confirm the grant type in use is supported -- client-credentials and ROPC grants are rejected when client authentication is disabled.
* **Verify the requested `scopes` are valid** for the authorization server -- invalid scopes may cause authorization failures.
* **If registration fails with a missing `registration_endpoint`**, the discovery document does not advertise one. That authorization server does not support Dynamic Client Registration; use static credentials or CIMD instead.
* **If the authorization server rejects a CIMD client as unknown**, fetch `cimd.url` from outside your network and confirm it returns the metadata document rather than a 404. The usual cause is the Orchestrator not being routable at that host and path.
* **If the configuration fails to load with `'url' must be lowercase`**, lowercase the entire `cimd.url`, host and path alike.
* **If either credential-less mode is ignored entirely**, check the Orchestrator version -- `dcr` and `cimd` require v2026.08.2 or later.

## Related Pages

> **[Identity Fabric](/reference/orchestrator/identity-fabric)**
>
> Overview of all identity providers

> **[Token Brokering](/reference/orchestrator/experimental/token-brokering)**
>
> RFC 8693 token exchange for downstream APIs

> **[Generic OIDC](/reference/orchestrator/identity-fabric/custom-oidc)**
>
> Generic OpenID Connect connector

> **[Generic SAML](/reference/orchestrator/identity-fabric/custom-saml)**
>
> Generic SAML 2.0 connector

> **[Client ID Metadata Documents](/reference/orchestrator/experimental/client-id-metadata-documents)**
>
> Accept CIMD clients as an OIDC Provider

> **[Experimental Features](/reference/orchestrator/experimental/overview)**
>
> Caveats that apply to experimental features
