|
| 1 | +--- |
| 2 | +title: Middleware |
| 3 | +description: Client-side route middleware for Shopify authentication and the built-in login page. |
| 4 | +navigation: |
| 5 | + icon: i-lucide-shield-check |
| 6 | +seo: |
| 7 | + title: Middleware — shopify-app-nuxt API Reference |
| 8 | + description: Reference for the shopify-auth route middleware and the default auth-login page component. |
| 9 | +--- |
| 10 | + |
| 11 | +## `shopify-auth` |
| 12 | + |
| 13 | +A **named** Nuxt route middleware that guards pages requiring an authenticated Shopify session. It is auto-registered by the module but **not global** — you opt-in per page. |
| 14 | + |
| 15 | +### How It Works |
| 16 | + |
| 17 | +| Environment | Check | Redirect | |
| 18 | +| --- | --- | --- | |
| 19 | +| **Server (SSR)** | Looks for the `shop` query parameter that Shopify always provides when loading an embedded app | Redirects to the auth page if missing | |
| 20 | +| **Client** | Checks `window.shopify.config.shop` from App Bridge | Redirects to the auth page if unavailable | |
| 21 | + |
| 22 | +If the check fails on either side, the middleware navigates to the auth page (default `/auth`). The path is configurable via `authPagePath` in the public runtime config. |
| 23 | + |
| 24 | +### Usage |
| 25 | + |
| 26 | +Add `definePageMeta({ middleware: 'shopify-auth' })` to any page that should require authentication: |
| 27 | + |
| 28 | +```vue |
| 29 | +<script setup> |
| 30 | +definePageMeta({ |
| 31 | + middleware: 'shopify-auth' |
| 32 | +}) |
| 33 | +</script> |
| 34 | +
|
| 35 | +<template> |
| 36 | + <ShPage title="Dashboard"> |
| 37 | + <!-- Only renders when authenticated --> |
| 38 | + </ShPage> |
| 39 | +</template> |
| 40 | +``` |
| 41 | + |
| 42 | +You can also apply it to a layout if all pages under that layout need protection: |
| 43 | + |
| 44 | +```vue |
| 45 | +<!-- layouts/default.vue --> |
| 46 | +<script setup> |
| 47 | +definePageMeta({ |
| 48 | + middleware: 'shopify-auth' |
| 49 | +}) |
| 50 | +</script> |
| 51 | +
|
| 52 | +<template> |
| 53 | + <ShopifyAppProvider> |
| 54 | + <slot /> |
| 55 | + </ShopifyAppProvider> |
| 56 | +</template> |
| 57 | +``` |
| 58 | + |
| 59 | +### Source |
| 60 | + |
| 61 | +```ts |
| 62 | +defineNuxtRouteMiddleware((to) => { |
| 63 | + const config = useRuntimeConfig().public.shopify |
| 64 | + const authPage = config.authPagePath || '/auth' |
| 65 | + |
| 66 | + if (import.meta.server) { |
| 67 | + const shop = to.query.shop as string | undefined |
| 68 | + if (!shop) return navigateTo(authPage) |
| 69 | + return |
| 70 | + } |
| 71 | + |
| 72 | + const shop = window.shopify?.config?.shop |
| 73 | + if (!shop) return navigateTo(authPage) |
| 74 | +}) |
| 75 | +``` |
| 76 | + |
| 77 | +--- |
| 78 | + |
| 79 | +## Default Auth Login Page |
| 80 | + |
| 81 | +The module ships a built-in `/auth` page (`auth-login.vue`) that provides a styled login form for merchants. It is automatically registered unless explicitly disabled. |
| 82 | + |
| 83 | +### What It Does |
| 84 | + |
| 85 | +1. Presents a centered card with the Shopify logo, a shop domain input field, and a **Log in** button |
| 86 | +2. Accepts a bare store name (e.g., `my-shop`) or a full domain (`my-shop.myshopify.com`) |
| 87 | +3. On submit, redirects the merchant to the OAuth flow at `{authPathPrefix}?shop={domain}` |
| 88 | + |
| 89 | +### Appearance |
| 90 | + |
| 91 | +The page renders with `layout: false` (no app shell) and uses self-contained scoped styles that match the Shopify admin aesthetic — no Polaris dependency required. |
| 92 | + |
| 93 | +### Controlling the Auth Page |
| 94 | + |
| 95 | +The `authPage` module option controls this page: |
| 96 | + |
| 97 | +| Value | Behavior | |
| 98 | +| --- | --- | |
| 99 | +| *(not set)* | Registers the default `auth-login.vue` at `/auth` | |
| 100 | +| `false` | Disables the built-in page entirely — you must handle the route yourself | |
| 101 | +| `'/path/to/MyLogin.vue'` | Registers your custom component at `/auth` instead | |
| 102 | + |
| 103 | +```ts |
| 104 | +// nuxt.config.ts |
| 105 | +export default defineNuxtConfig({ |
| 106 | + shopify: { |
| 107 | + // Use defaults (built-in login page at /auth) |
| 108 | + // authPage: undefined |
| 109 | + |
| 110 | + // Disable the built-in page |
| 111 | + // authPage: false |
| 112 | + |
| 113 | + // Use a custom component |
| 114 | + // authPage: '~/components/MyShopifyLogin.vue' |
| 115 | + } |
| 116 | +}) |
| 117 | +``` |
| 118 | + |
| 119 | +### Overriding the Page |
| 120 | + |
| 121 | +To fully customize the login experience while keeping the same route, create your own component and point `authPage` to it. Your component should: |
| 122 | + |
| 123 | +1. Collect the shop domain from the merchant |
| 124 | +2. Redirect to `{authPathPrefix}?shop={domain}` with `external: true` |
| 125 | + |
| 126 | +```vue |
| 127 | +<!-- components/MyShopifyLogin.vue --> |
| 128 | +<script setup> |
| 129 | +definePageMeta({ layout: false }) |
| 130 | +
|
| 131 | +const shop = ref('') |
| 132 | +const config = useRuntimeConfig() |
| 133 | +
|
| 134 | +function login() { |
| 135 | + const domain = shop.value.includes('.myshopify.com') |
| 136 | + ? shop.value |
| 137 | + : `${shop.value}.myshopify.com` |
| 138 | + navigateTo( |
| 139 | + `${config.public.shopify.authPathPrefix}?shop=${encodeURIComponent(domain)}`, |
| 140 | + { external: true } |
| 141 | + ) |
| 142 | +} |
| 143 | +</script> |
| 144 | +
|
| 145 | +<template> |
| 146 | + <form @submit.prevent="login"> |
| 147 | + <input v-model="shop" placeholder="your-shop" /> |
| 148 | + <button type="submit">Install</button> |
| 149 | + </form> |
| 150 | +</template> |
| 151 | +``` |
0 commit comments