Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 45 additions & 26 deletions platforms/android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
- [Preload checkout](#preload-checkout)
- [Configure checkout](#configure-checkout)
- [Color schemes](#color-schemes)
- [Incoming message origin validation](#incoming-message-origin-validation)
- [Title localization](#title-localization)
- [Current configuration](#current-configuration)
- [Checkout lifecycle](#checkout-lifecycle)
Expand Down Expand Up @@ -258,8 +259,8 @@ ShopifyCheckoutKit.configure {
| `sheet` | `CheckoutSheetOptions()` | Customize native sheet presentation such as snap points, dismissal behavior, corner radius, title alignment, toolbar elevation, close icon styling, and the optional drag handle. |
| `logLevel` | `LogLevel.WARN` | SDK logging verbosity. Use `LogLevel.DEBUG` during integration. |
| `preloading` | `Preloading(enabled = true)` | Enables best-effort checkout preloading before presentation. |
| `allowedMessageOrigins` | `emptySet()` | Extra origins allowed to send checkout protocol messages. |
| `onMessageRejected` | `null` | Observes messages rejected by origin validation. |
| `allowedMessageOrigins` | `emptySet()` | Origins trusted to send incoming checkout messages. Empty trusts every origin (open by default). See [Incoming message origin validation](#incoming-message-origin-validation). |
| `onMessageRejected` | `null` | Callback invoked when a message is dropped by origin validation. Defaults to logging at debug level. |

### Color schemes

Expand Down Expand Up @@ -348,6 +349,48 @@ Set `dragHandle.visible = true` to show a fixed, visual-only drag handle at the
when `dismissal.dragToDismissEnabled = false` so disabled drag gestures are not presented as available. Configure
`dragHandleColor` in `ColorScheme` to override the default header-font-derived handle color.

### Incoming message origin validation

The native WebView is a private, app-controlled runtime, so Checkout Kit is
**open by default**: with an empty `allowedMessageOrigins`, incoming
checkout-protocol messages from any origin are accepted. Provide one or more
origins to restrict which origins are trusted; the loaded checkout origin and
`shop.app` (including its subdomains) are always trusted as well.

```kotlin
ShopifyCheckoutKit.configure {
it.allowedMessageOrigins = setOf(
"https://checkout.example.com",
"https://*.example.com",
)
}
```

Each entry may be an exact origin (`https://example.com`), a wildcard subdomain
(`https://*.example.com`, matching subdomains but not the apex), or `"*"` to
explicitly trust every origin.

Exact and wildcard entries accept an optional trailing slash. Exact entries
must not include credentials, paths, queries, or fragments. For example,
`https://example.com/` is accepted, while `https://user@example.com` and
`https://example.com/path` are ignored.

Messages dropped by origin validation are logged at debug level. To observe
them instead, set `onMessageRejected`:

```kotlin
ShopifyCheckoutKit.configure {
it.onMessageRejected = { rejected ->
Log.w("Checkout", "Dropped ${rejected.origin}: ${rejected.reason}")
}
}
```

> [!WARNING]
> The `RejectedMessage` payload is untrusted — it was dropped precisely because
> its origin was not in the allowlist. Incoming messages are advisory and are
> never treated as an authoritative source of checkout state.

### Title localization

Override `checkout_web_view_title` in your app resources:
Expand All @@ -364,30 +407,6 @@ Override `checkout_web_view_title` in your app resources:
val configuration = ShopifyCheckoutKit.getConfiguration()
```

### Incoming message origin validation

Native checkout accepts messages from every origin by default. To restrict messages, configure one
or more exact origins or wildcard subdomains. The checkout URL's origin and `shop.app` remain
trusted automatically.

```kotlin
ShopifyCheckoutKit.configure {
it.allowedMessageOrigins = setOf(
"https://checkout.example.com",
"https://*.example.org",
)
it.onMessageRejected = { rejection ->
reportRejectedOrigin(rejection.origin, rejection.reason)
}
}
```

Exact entries accept an optional trailing slash, but not credentials, paths, queries, or fragments.
For example, `https://checkout.example.com/` is accepted, while
`https://user@checkout.example.com` and `https://checkout.example.com/path` are ignored. Wildcard
entries require the scheme and match subdomains only; `https://*.example.org` does not match
`https://example.org`. Use `"*"` to explicitly disable origin validation.

## Checkout lifecycle

Use `onFail` and `onDismiss` for checkout outcomes handled by your app. Use `CheckoutProtocol.Client` for typed checkout state, including completion. These descriptors wrap checkout protocol messages defined in the [protocol schema](../../protocol/services/shopping/embedded.openrpc.json).
Expand Down
41 changes: 41 additions & 0 deletions platforms/react-native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ experiences.
- [Usage with the Shopify Storefront API](#usage-with-the-shopify-storefront-api)
- [Configuration](#configuration)
- [Colors](#colors)
- [Incoming message origin validation](#incoming-message-origin-validation)
- [Localization](#localization)
- [Checkout Sheet title](#checkout-sheet-title)
- [iOS - Localization](#ios---localization)
Expand Down Expand Up @@ -345,6 +346,7 @@ instance of the `ShopifyCheckout` class.
| `preloading` | | `true` | Enable/disable [preloading](#preloading). |
| `colors` | | `{}` | An object with `ios` and `android` properties to override the colors for iOS and Android platforms individually. See [`colors`](#colors) for more information. |
| `logLevel` | | `error` | Sets the log level for the native SDK. Use `LogLevel.debug` for verbose logging during development, or `LogLevel.error` for production. |
| `allowedMessageOrigins` | | `[]` | Origins trusted to send incoming checkout messages. Empty trusts every origin (open by default). See [Incoming message origin validation](#incoming-message-origin-validation). |

Here's an example of how a fully customized configuration object might look:

Expand Down Expand Up @@ -387,6 +389,45 @@ function AppWithContext() {
const shopifyCheckout = new ShopifyCheckout(config);
```

### Incoming message origin validation

Checkout Kit runs on the native iOS and Android web views, which are private,
app-controlled runtimes. It is therefore **open by default**: with an empty
`allowedMessageOrigins`, incoming checkout-protocol messages from any origin are
accepted. Provide one or more origins to restrict which origins are trusted; the
loaded checkout origin and `shop.app` (including its subdomains) are always
trusted as well.

```tsx
const config: Configuration = {
allowedMessageOrigins: [
'https://checkout.example.com',
'https://*.example.com',
],
};
```

Each entry may be an exact origin (`https://example.com`), a wildcard subdomain
(`https://*.example.com`, matching subdomains but not the apex), or `'*'` to
explicitly trust every origin. Exact and wildcard entries accept an optional
trailing slash. Exact entries must not include credentials, paths, queries, or
fragments. Messages dropped by origin validation are logged by the native SDK
at debug level. To observe them instead, configure `onMessageRejected`:

```tsx
const config: Configuration = {
allowedMessageOrigins: ['https://checkout.example.com'],
onMessageRejected: ({origin, message, reason}) => {
console.warn(`Dropped message from ${origin}: ${reason}`, message);
},
};
```

> [!NOTE]
> Incoming messages are advisory (lifecycle/UI signals) and are never treated as
> an authoritative source of checkout state, so origin validation is defense in
> depth.

### Colors

The SDK defaults to the `automatic` color scheme option, will switches between
Expand Down
55 changes: 55 additions & 0 deletions platforms/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Check out our blog to
- [`target`](#target)
- [`appearance`](#appearance)
- [`log-level`](#log-level)
- [`allowed-origins`](#allowed-origins)
- [`onMessageRejected`](#onmessagerejected)
- [Popup dimensions](#popup-dimensions)
- [Overlay scrim](#overlay-scrim)
- [Checkout lifecycle](#checkout-lifecycle)
Expand Down Expand Up @@ -397,6 +399,59 @@ Use `"debug"` while wiring up `src` and event handlers during integration, or
checkout.logLevel = 'debug';
```

### `allowed-origins`

Controls which origins are trusted to post incoming checkout-protocol messages
to the component. On web, checkout is **closed by default**: with no configured
origins, only the cart URL origin (from `src`) and `shop.app` (including its
subdomains) are trusted. Messages from any other origin are dropped.

Provide extra origins as a space- or comma-separated list. Each entry may be:

| Entry | Matches |
| ------------------------- | -------------------------------------------------------------- |
| `https://example.com` | That exact origin. |
| `https://*.example.com` | Any subdomain of `example.com` (not the apex `example.com`). |
| `*` | Every origin — disables origin validation entirely. |

Exact and wildcard entries accept an optional trailing slash. Exact entries
must not include credentials, paths, queries, or fragments. For example,
`https://example.com/` is accepted, while `https://user@example.com` and
`https://example.com/path` are ignored.

```html
<shopify-checkout src="..." allowed-origins="https://checkout.example.com https://*.example.com" />
Comment thread
tiagocandido marked this conversation as resolved.
```

```ts
checkout.allowedOrigins = ['https://checkout.example.com', 'https://*.example.com'];
```

> [!NOTE]
> Incoming messages are advisory (lifecycle/UI signals) and are never treated
> as an authoritative source of checkout state, so origin validation is defense
> in depth. Use `*` only when you understand the trade-off — in the shared
> browser, other pages and extensions can post to the component.

Invalid entries are ignored, and a warning is logged at `log-level="warn"` or
more verbose.

### `onMessageRejected`

A property-only callback invoked whenever an incoming message is dropped by
origin validation. The smart default logs a warning; assign a function to
observe rejected messages instead (for example, to report them).

```ts
checkout.onMessageRejected = ({ origin, data, reason }) => {
console.warn(`Dropped message from ${origin}: ${reason}`, data);
};
```

> [!WARNING]
> The payload is untrusted — it was dropped precisely because its origin was
> not in the allowlist. Do not derive checkout state from it.

### Popup dimensions

When `target="popup"`, the popup is centered over the host window. Defaults
Expand Down
Loading