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

# Shopify Authentication

> Authenticate Omneo API calls from Shopify Liquid themes and App UI Extensions using the Omneo ID Proxy.

Client-side code on Shopify cannot use a standard Omneo API key. An API key has access to every profile in the tenant, so embedding one in a Liquid template or an App UI Extension would expose all customer data.

Instead, all client-side requests authenticate through the **Omneo ID Proxy**, which issues short-lived, customer-scoped tokens. This guide covers the two ways to obtain an ID Proxy token from a Shopify surface and how to use the token with the `@omneo/omneo-sdk` package.

<Info>
  This guide is part of the [Shopify extension](/extensions/shopify/overview). For SDK fundamentals see [Omneo SDK](/dev-guides/core-setup/sdk).
</Info>

## Authentication methods

The right method depends on where your code runs.

| Surface              | Method                                      | Why                                                                                                                                                                                |
| -------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Shopify Liquid theme | `GET /apps/cx` (Omneo CX Shopify app proxy) | The Omneo CX app exposes a proxy route that Shopify automatically authenticates against the storefront session.                                                                    |
| App UI Extension     | Host-owned Remix server route               | UI Extensions run in a sandboxed web worker that cannot reach `/apps/cx`. A server route under your own app validates a Shopify session token and exchanges it for an Omneo token. |

The token returned in both cases is the same kind: a short-lived ID Proxy token scoped to a single customer (or anonymous if no customer is logged in).

## Liquid themes: `/apps/cx`

In a Shopify Liquid theme with the Omneo CX Shopify app installed, make an unauthenticated `GET` request to `/apps/cx`. Shopify routes the request through the app proxy and returns a token.

```javascript theme={null}
const response = await fetch('/apps/cx')
const { token, expiry } = await response.json()
const tenant = response.headers.get('x-omneo-tenant')
const isAnonymous = response.headers.get('x-omneo-is-anon') === 'true'
```

The response includes:

| Field             | Source | Description                           |
| ----------------- | ------ | ------------------------------------- |
| `token`           | body   | The ID Proxy token to pass to the SDK |
| `expiry`          | body   | Token expiry timestamp                |
| `x-omneo-tenant`  | header | The Omneo tenant the token belongs to |
| `x-omneo-is-anon` | header | `true` when no customer is logged in  |

### Anonymous vs customer-scoped tokens

`/apps/cx` returns one of two token kinds depending on Shopify's customer state:

* **Anonymous token** when no customer is logged in. Limited to endpoints that allow anonymous access (for example, reading a shared list by handle).
* **Customer-scoped token** when a customer is logged in. Grants access only to that customer's profile and related resources.

Discard the token when the customer logs out, and request a new one on the next page load.

## App UI Extensions: Remix-hosted route

App UI Extensions run in a sandboxed web worker. The worker can't reach `/apps/cx` directly, so your Remix app needs a server route that performs the token exchange on the extension's behalf.

The flow:

<Steps>
  <Step title="Fetch a Shopify session token in the extension">
    Use the `useSessionToken` hook (or equivalent) in the UI Extension to obtain a session token for the current Shopify session.
  </Step>

  <Step title="POST the session token to your Remix route">
    Send the session token to a server route hosted by your Remix app, for example `/api/omneo/token`.
  </Step>

  <Step title="Validate the session token server-side">
    The Remix route verifies the session token against Shopify, then calls the Omneo ID Proxy using your server-side credentials to obtain an ID Proxy token for the customer.
  </Step>

  <Step title="Return the ID Proxy token to the extension">
    The Remix route responds with the ID Proxy token, tenant, and expiry. The extension uses these to initialise the SDK.
  </Step>
</Steps>

<Note>
  Reference implementations for the Remix route and a UI Extension that consumes it are available from your Omneo implementation team.
</Note>

## Using the token with `@omneo/omneo-sdk`

Once you have a token, tenant, and expiry from either method, initialise the SDK `ID` client. The same client is used for both Liquid and UI Extension surfaces.

```javascript theme={null}
import { ID } from '@omneo/omneo-sdk'

const client = new ID({
  tenant,
  IDToken: token,
  IDTokenExpiry: expiry
})
```

All subsequent calls on `client` are automatically scoped to the customer the token was issued for. See [Shopify Lists](/extensions/shopify/lists) for a worked example using this client.

## Security notes

* Tokens are short-lived and scoped to a single profile. They cannot be used to access other profiles.
* Never embed a long-lived Omneo API key in Liquid templates, theme JavaScript, or UI Extension code.
* The Shopify shared secret used by the Remix route to validate session tokens must stay server-side.
* Discard tokens on logout. Do not persist a customer-scoped token past the end of the customer's session.
