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

# Auth proxy

> Set up the Swish auth proxy to securely create API tokens from headless storefronts.

The auth proxy securely creates Swish API tokens on your server using your app secret. The client SDK then uses these tokens to communicate directly with the Swish API.

On Shopify themes, token creation is handled automatically by the app proxy. Headless environments - Hydrogen, Next.js, or any custom storefront - need to run their own token endpoint using the `@swishapp/auth-proxy` package.

> [!NOTE]
>
> If you're using a Shopify theme, skip this page. Token creation is already
> handled for you.

## Installation

```bash npm theme={null}
npm install @swishapp/auth-proxy
```

```bash pnpm theme={null}
pnpm add @swishapp/auth-proxy
```

```bash yarn theme={null}
yarn add @swishapp/auth-proxy
```

## Quick start

Create an auth proxy instance and expose `createToken` as a server route. The proxy validates the request, creates a token using the Swish API, and returns it to the client.

```ts theme={null}
import { createAuthProxy } from "@swishapp/auth-proxy";

const proxy = createAuthProxy({
  authToken: process.env.SWISH_API_TOKEN,
  authenticate: async (request) => {
    const customerId = await getLoggedInCustomerId(request);
    return customerId;
  },
});

// In your route handler:
const response = await proxy.createToken(request);
```

## Configuration

| Option | Type | Required | Description |
| - | - | - | - |
| `authToken` | `string \| (request: Request) => string \| Promise<string>` | Yes | Your Swish API token. Pass a function to resolve the token per-request (e.g. for multi-tenant setups). Must be stored securely and never exposed client-side. |
| `authenticate` | `(request: Request) => string \| null \| Promise<string \| null>` | Yes | Returns the authenticated Shopify customer ID for the request, or `null` for guest visitors. |
| `onError` | `(error: unknown) => void` | No | Called when an unexpected error occurs during token creation. |
| `apiUrl` | `string` | No | Override the Swish API origin the proxy forwards to (default `https://swish.app`, version-routed). When set, requests go to `${apiUrl}/profiles/token` as-is, bypassing version routing. Mainly for local development against a self-hosted Swish API. |

## How it works

When `createToken(request)` is called:

1. The proxy calls your `authenticate` callback to identify the customer.
2. It reads the request body and forwards it to `POST /profiles/token` on the Swish API, authenticated with your `authToken`.
3. If the body contains a `customer` field, the proxy validates that it matches the authenticated customer ID. A mismatch returns a `401` response. This prevents a client from requesting tokens for other customers.
4. The upstream response is returned directly to the client.

Any unexpected error is passed to `onError` and returned to the client as a `401`.

## Framework examples

### Hydrogen

Expose the proxy as a Remix action on a server route.

```ts app/routes/api.swish-token.ts theme={null}
import type { ActionFunctionArgs } from "react-router";
import { createAuthProxy } from "@swishapp/auth-proxy";

const proxy = createAuthProxy({
  authToken: process.env.SWISH_API_TOKEN,
  authenticate: async (request) => {
    const session = await getSession(request);
    return session?.customerId ?? null;
  },
  onError: (error) => console.error("Swish auth proxy error:", error),
});

export async function action({ request }: ActionFunctionArgs) {
  return proxy.createToken(request);
}
```

### Next.js

Expose the proxy as a Route Handler.

```ts app/api/swish-token/route.ts theme={null}
import { createAuthProxy } from "@swishapp/auth-proxy";

const proxy = createAuthProxy({
  authToken: process.env.SWISH_API_TOKEN!,
  authenticate: async (request) => {
    const session = await getSession(request);
    return session?.customerId ?? null;
  },
  onError: (error) => console.error("Swish auth proxy error:", error),
});

export async function POST(request: Request) {
  return proxy.createToken(request);
}
```

## SDK configuration

Configure the SDK to use your auth proxy route by setting `auth.tokenUrl` to match the server endpoint you created above.

```ts theme={null}
const swish = await createSwish({
  auth: {
    tokenUrl: "/api/swish-token",
  },
  storefront: { ... },
  context: { ... },
});
```

On Shopify themes this defaults to `/apps/wishlist/api/profiles/token` and does not need to be set.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.