Skip to main content
GET
/
apps
/
oauth
/
authorize
Authorize
curl --request GET \
  --url https://api.launchmystore.io/apps/oauth/authorize \
  --header 'Authorization: Bearer <token>'
{
  "status": 123,
  "state": "<string>",
  "data": {
    "code": "<string>",
    "state": "<string>",
    "redirectUri": "<string>",
    "app": {}
  }
}

Documentation Index

Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt

Use this file to discover all available pages before exploring further.

Authorize

Starts the OAuth 2.0 authorization code grant flow. The merchant must be signed in to their LaunchMyStore admin when this endpoint is hit — the endpoint is protected by merchant auth and uses the merchant’s session to resolve which storeId is granting consent. On success, the endpoint returns a one-time code plus an opaque state your app must round-trip to POST /apps/oauth/token to exchange for an access token.
The state parameter returned by this endpoint is server-generated and bound to the authorization code in Redis with a 10-minute TTL. You must echo it back on the token exchange call. Your own anti-CSRF token, if any, should be passed in the request as a separate value and is not read by the server.

Request

curl -X GET "https://api.launchmystore.io/apps/oauth/authorize?\
client_id=lms_app_xxx&\
redirect_uri=https://your-app.com/oauth/callback&\
scope=read_products,write_products,read_orders&\
response_type=code&\
code_challenge=BASE64URL(SHA256(verifier))&\
code_challenge_method=S256" \
  -H "Authorization: Bearer MERCHANT_JWT"

Query Parameters

client_id
string
required
The app’s public client identifier. Issued when the developer registers the app via POST /apps/developer/create.
redirect_uri
string
required
The callback URL where the merchant will be redirected after consent. Must exactly match one of the URLs in app.redirectUrls. Mismatched URIs return 400 Invalid redirect URI.
scope
string
required
Comma-separated list of scopes being requested (e.g. read_products,write_orders). Each scope must be a member of the app’s registered scope set; otherwise the endpoint returns 400 Invalid scopes: <list>. See Scopes for the 37 available scopes.
response_type
string
default:"code"
Must be code. Any other value returns 400 Unsupported response_type. Defaults to code when omitted for back-compat.
state
string
Optional client-side anti-CSRF nonce. The server stores this in clientState and returns it untouched alongside the server-generated state for your reference. Not used for server-side validation.
code_challenge
string
PKCE (RFC 7636) code challenge. When supplied, the matching code_verifier must be sent on the token exchange. Length must be 43-128 characters.
code_challenge_method
string
default:"plain"
Either S256 (strongly recommended) or plain. Any other value returns 400. Only meaningful when code_challenge is also sent.

Response

status
integer
HTTP status code (200 on success).
state
string
Final response state: "success" or "error".
data
object

Example Response

{
  "status": 200,
  "state": "success",
  "data": {
    "code": "9fbb1c3e8d4a7b2e0a5d6f7c8b9e0d1c2a3b4c5d6e7f8091a2b3c4d5e6f70819",
    "state": "5d6f7c8b9e0d1c2a3b4c5d6e7f80910a2b3c4d5e6f70819b8c4d5e6f7081923a",
    "redirectUri": "https://your-app.com/oauth/callback",
    "app": {
      "name": "Foundry Reviews",
      "description": "Customer reviews with photos and Q&A",
      "developer": "Foundry Apps",
      "iconUrl": "https://cdn.launchmystore.io/apps/foundry-reviews/icon.png",
      "scopes": ["read_products", "write_metafields", "read_orders"]
    }
  }
}
Your app should now redirect the merchant back to your redirect_uri with code and state appended as query parameters, then immediately call POST /apps/oauth/token server-side.
import crypto from 'crypto';

// 1. Generate verifier + challenge
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto
  .createHash('sha256')
  .update(codeVerifier)
  .digest('base64url');

// 2. Authorize with the challenge
const authUrl = new URL('https://api.launchmystore.io/apps/oauth/authorize');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('scope', 'read_products,write_metafields');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');

// 3. On the callback, exchange code+verifier (no client_secret needed for PKCE)
//    See: /api-reference/oauth/token

Error Codes

HTTPError messageWhen
400Invalid redirect URIredirect_uri not in app.redirectUrls
400Invalid scopes: <names>One or more requested scopes not registered on the app
400Unsupported response_typeresponse_type is anything other than code
400Invalid code_challenge_methodNot S256 or plain
400code_challenge must be 43-128 charactersPKCE challenge length out of range
401(auth guard)No valid merchant session on the request
404App not found or not publishedclient_id does not match a published app

Security Notes

  • Authorization codes are stored in Redis with a 10-minute TTL and are single-use. Replays of an already-consumed code fail with Invalid or expired authorization code on the token endpoint.
  • The server-generated state is bound to the code in Redis. Both are deleted atomically when the token is issued.
  • This endpoint is not rate-limited at the gateway (@SkipThrottle) — it is already gated by merchant authentication.
  • For embedded apps, prefer PKCE + session tokens. See Session Tokens.