Skip to main content

Install handoff (/auth)

When a merchant clicks Install on your app in the LaunchMyStore marketplace and confirms the consent screen, we redirect their browser to your app’s /auth endpoint with an HMAC-signed query string. Your /auth handler is the entry point for every install — it verifies the request is genuinely from us, exchanges a pre-authorized code for an access token, and lands the merchant back inside their admin. The same handoff fires for private apps installed via the Developer Portal’s Install on My Store button — there is no consent screen (you are installing on your own store), but the browser is redirected to your /auth URL with the same code/state/hmac parameters. This is how a private app obtains its first Admin API access token; no marketplace publication is required. If your app’s appUrl is an external URL (anything starting with https://), you must serve /auth. First-party apps with local /marketplace-apps/... URLs do not receive this redirect and stay embedded directly.

The redirect we send

After the merchant approves install, LaunchMyStore navigates the browser to:

Parameters

Step 1: Verify the HMAC

Reconstruct the querystring without the hmac field, compute HMAC-SHA256 with your clientSecret, and compare in constant time.
Always use constant-time comparison (crypto.timingSafeEqual in Node, hmac.compare_digest in Python, Rack::Utils.secure_compare in Ruby). String == leaks timing information.

Step 2: Exchange the code for an access token

Once HMAC is verified, call our token endpoint with your client_id, client_secret, the code, and the state. No merchant session cookie is needed — your client credentials are the auth.
Response — the token object is wrapped in the platform envelope ({ status, state, message, data }); read the fields from data:
The code is single-use. A second exchange attempt returns 400 Invalid or expired authorization code.

Step 3: Persist the install record

Store the install keyed by storeId, not shop:
The merchant may later change their shop domain (rename mystore.launchmystore.io or attach www.merchant-domain.com). If you keyed off shop you would lose every install on rename. storeId never changes.

Step 4: Land the merchant in their admin

Decode the host parameter to get the URL of the merchant’s embedded admin view, then redirect there:
The merchant lands inside their LaunchMyStore admin with your app embedded as an iframe. From there your app authenticates per-request via session tokens — no further OAuth round trip is needed for normal use.

Full reference implementation

When /auth is and isn’t called

Lost your access token? The merchant admin can re-issue the handoff for an active install via GET /apps/store/launch-url/:appId (merchant-authed) — opening the returned URL fires your /auth endpoint with a fresh single-use code. Uninstall + reinstall also works. There is no separate “retrieve my token” endpoint; tokens are only ever delivered through this handoff, so persist the access_token + refresh_token pair durably (encrypted at rest, keyed by storeId).
For the merchant-opens-app case, use session tokens to authenticate per-request. The /auth handoff happens once per install; session tokens happen on every render.

Parameter quick reference

For convenience, the redirect query parameters at a glance: The contract uses standard OAuth 2.0 (RFC 6749) authorization code grant semantics plus an HMAC-signed install redirect. Any HTTP framework can implement it in under 50 lines.

Common errors