Authentication
App launch from the merchant dashboard
What your launch URL receives on install and on open, and how to confirm that LARM issued the URL just now.
When the launch URL is opened
LARM opens the launch_url registered in your app version in two cases:
larm_intent | When | What to do |
|---|---|---|
install | The merchant clicked "Install" | Start authorization for this store |
open | The merchant opened the installed app from the dashboard | Start the merchant's session in your app |
There is no separate app.installed webhook; you learn about the install from this URL and then from the code exchange.
Parameters
LARM removes any parameters starting with larm_ from your URL, then appends:
| Parameter | Value |
|---|---|
larm_store_id | Store UUID |
larm_installation_id | Installation UUID, with open only |
larm_intent | install or open |
larm_issued_at | Issue time in Unix seconds |
larm_nonce | 24 random base64url characters |
larm_signature | 43 base64url characters |
Example:
https://app.example.com/larm/launch?larm_store_id=5b1d7a62-0c4e-4f38-9a51-2e7b3c9d8f10&larm_installation_id=c7e4a1f2-6b3d-4e8a-9c05-1d2f3a4b5c6d&larm_intent=open&larm_issued_at=1792060800&larm_nonce=Vx3mQ0aT9kLz2pR8sN4wYb1c&larm_signature=8m2Kq…Verify the URL
The signature uses a key that only LARM holds, so you cannot verify it locally. Send the parameters exactly as received to [POST /oauth/launch/verify](/api/oauth-launch-verify) from your server:
const params = Object.fromEntries(
[...new URL(req.url, 'https://app.example.com').searchParams].filter(([key]) => key.startsWith('larm_')),
)
const response = await fetch('https://larm.sa/oauth/launch/verify', {
method: 'POST',
headers: {
Authorization: 'Basic ' + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64'),
'Content-Type': 'application/json',
},
body: JSON.stringify(params),
})
if (!response.ok) return res.status(401).send('Invalid launch URL')
const launch = await response.json()
// { valid: true, store_id, installation_id, intent, issued_at }- The body carries
larm_*keys only, all as strings. Any other key returns 400INVALID_LAUNCH. - The URL is valid for 5 minutes from
larm_issued_at. After that: 401LAUNCH_EXPIRED. - With
open, the installation must be active; otherwise 401INSTALLATION_INACTIVE. - A wrong signature returns 401
LAUNCH_SIGNATURE_INVALID.
Start the merchant's session
The launch URL carries no access token and grants no access. After verification:
- Look up the
installation_idin your database. If it is not there, orintent=install, start authorization. - Create a session in your app bound to
store_id, with anHttpOnly,Secure,SameSite=Laxcookie. - Redirect the browser to your app page without the
larm_*parameters, so they do not stay in history or in theRefererheader.
Your app opens in its own window, not in a frame inside the merchant dashboard.