# OAuth for apps

> Use an app as an OAuth client of Kustomer so your service can act as a user, or configure auth.oauth2 so Kustomer connects to a third-party API on the admin's behalf.

Source: https://developer.kustomer.com/docs/apps/oauth

OAuth works in both directions on the apps platform:

| You want                                                                             | Kustomer is the | Configure                            |
| ------------------------------------------------------------------------------------ | --------------- | ------------------------------------ |
| Your hosted service to call the **Kustomer API** as the user who connected it        | OAuth provider  | `redirectUris`, plus a client secret |
| Your app's actions and commands to call a **third-party API** with the admin's grant | OAuth client    | `auth.oauth2`                        |

## Call Kustomer as a user

Every app has a client ID. To let users sign in to your service with Kustomer and call the API on their behalf, declare your redirect URIs, register and install the app, and mint a client secret.

```mermaid
sequenceDiagram
  autonumber
  participant Dev as You
  participant Apps as Kustomer
  participant User as Kustomer user
  Dev->>Apps: POST /v1/apps/available (with redirectUris)
  Apps-->>Dev: clientId
  User->>Apps: Install the app in their org
  Dev->>Apps: POST /v1/apps/available/{app}-{version}/secret
  Apps-->>Dev: clientSecret (shown once)
  User->>Apps: Authorize your service (OAuth authorization code flow)
  Apps-->>Dev: access_token + refresh_token
```

#### Declare redirect URIs

```json title="Definition"
{
  "app": "acme_assistant",
  "version": "1.0.0",
  "title": "Acme Assistant",
  "visibility": "private",
  "redirectUris": ["https://assistant.acme.example/oauth/callback"]
}
```

`title` is what users see on the consent screen, so make it recognizable.

#### Register and install

Register with `POST /v1/apps/available` (see [Register and install](https://developer.kustomer.com/docs/apps/register-and-install)). The response's `attributes.clientId` is your client ID. Then install the app in the org. Authorization fails with an `Invalid Client` error (`400`) in any org where the app isn't installed.

#### Mint a client secret

`POST /v1/apps/available/{app}-{version}/secret`

```bash title="cURL"
curl -X POST "https://acme.api.kustomerapp.com/v1/apps/available/acme_assistant_${ORG_ID}-1.0.0/secret" \
  -H "Authorization: Bearer $KUSTOMER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

Private app names carry your org ID suffix, so use the registration response's `id`, which is `<app>-<version>`. The response contains the `clientSecret`, shown only this once; store it in your secrets manager. Calling the endpoint again generates a new secret.

#### Run the authorization code flow

Send the user to their org's authorize URL, exchange the code, and refresh tokens as described in [OAuth 2.0](https://developer.kustomer.com/docs/get-started/oauth). Request the roles you need as scopes, such as `org.permission.customer org.permission.conversation`, and add `offline_access` to get a refresh token.

**Tokens**

When an admin disables the app, Kustomer revokes the tokens it issued to the app's client. Users sign in again after it's re-enabled.

## Call third-party APIs with OAuth

To call an API that uses OAuth 2.0 (a CRM, a commerce platform, a ticketing tool) add `auth.oauth2`. When an admin connects the app, Kustomer sends them through the provider's consent screen, stores the resulting token as the app's **app account**, keeps it refreshed, and injects it into every action and command that names that account.

```json title="auth (excerpt)"
{
  "auth": {
    "oauth2": {
      "clientId": "acme_9f2c41",
      "clientSecret": "s3cr3t-from-acme",
      "clientCredentialsMethod": "basicAuth",
      "authorizationUrl": "https://acme.example/oauth/authorize",
      "tokenUrl": "https://api.acme.example/oauth/token",
      "authorizationScope": "orders:read refunds:write",
      "revokeUrl": "https://api.acme.example/oauth/revoke",
      "expiresIn": 3600
    }
  },
  "actions": [
    {
      "name": "kustomer.app.acme_orders.refund",
      "type": "rest_api",
      "appAccountName": "default",
      "inputTemplate": { "uri": "https://api.acme.example/orders/{{orderId}}/refunds", "method": "POST", "json": true }
    }
  ],
  "commands": [
    {
      "name": "acme_orders.app.lookup-order",
      "url": "https://api.acme.example/orders/{{{orderId}}}",
      "httpMethod": "get",
      "permittedArgs": ["orderId"],
      "appAccountName": "default"
    }
  ]
}
```

**auth.oauth2**

### Register Kustomer's redirect URI with the provider

Providers only redirect to URIs you've registered with them. Kustomer uses one static URI per app, so it works with providers that require an exact match:

```text
https://api.apps.kustomerapp.com/v1/apps/<app>/authorize/oauth2/redirect
```

Replace `<app>` with your app's name, including the `_<orgId>` suffix for private apps.

### What admins see

1. An admin connects the app from its page in Kustomer, which opens the provider's consent screen with your `authorizationScope`.
2. After the admin approves, the provider redirects back with a code, which Kustomer exchanges at `tokenUrl`. The admin has 10 minutes to complete this before the attempt expires.
3. The token is stored, encrypted with the org's own key, as the app account named `default`. Each app has one app account.

### How the token is used

Any action or command with `"appAccountName": "default"` gets the token added to its request:

| `customHeader`   | Header sent                     |
| ---------------- | ------------------------------- |
| Not set          | `Authorization: Bearer <token>` |
| `"X-Acme-Token"` | `X-Acme-Token: <token>`         |

If a request fails because the provider rejected the token, Kustomer records the error on the app account so the broken connection is visible. The admin fixes it by connecting again. Disabling the app deletes its OAuth connections, so admins must reconnect after re-enabling it.

### Without OAuth

If the third-party API uses a static key instead, skip `auth` and store the key in a [`secret` setting](https://developer.kustomer.com/docs/apps/settings#secrets), referenced through `appSettings` in your actions and commands.
