Client Credentials
Client Credentials
Client credentials provide server-to-server authentication for apps that need to make API calls without a user session. This is the simplest authentication method and works well for background processes, cron jobs, and webhook handlers.
Headers
Every request using client credentials must include all three headers:
X-Client-Id: sx_app_...
X-Client-Secret: sx_secret_...
X-Store-Id: 22
| Header | Description |
|---|---|
X-Client-Id | Your app's client ID (issued on app creation) |
X-Client-Secret | Your app's client secret (issued on app creation) |
X-Store-Id | The store ID to operate on (must have an active installation) |
All three headers are required on every request. Omitting X-Client-Id or X-Client-Secret returns 401 Unauthorized. Omitting X-Store-Id returns 400 Bad Request.
When to Use Client Credentials
Use client credentials instead of OAuth Bearer tokens when:
- Background jobs and cron tasks -- Your server needs to pull or push data on a schedule without merchant interaction
- Webhook processing -- After receiving a webhook, your app needs to make API calls back to the platform to fetch additional data or update resources
- Server-side integrations -- Backend services that interact with the SeloraX API without any user-facing flow
- Initial setup before OAuth -- When bootstrapping an app's connection before the full OAuth flow is configured
Key Properties
- Never expire -- Client credentials function like Shopify offline access tokens. Once issued, they remain valid until explicitly rotated.
- Same API access as Bearer tokens -- Any endpoint accessible with an OAuth Bearer token can also be accessed with client credentials. The permission scope is determined by the app's installation.
- Validated per-request -- The platform verifies the client ID, secret, and store ID on every request. No token storage or refresh logic is needed on your end.
- All 3 headers required -- Unlike OAuth where a single
Authorizationheader suffices, client credentials require all three headers to identify both the app and the target store.
Example
Node.js (fetch)
const response = await fetch('https://api.selorax.io/api/apps/v1/orders', {
headers: {
'X-Client-Id': process.env.CLIENT_ID,
'X-Client-Secret': process.env.CLIENT_SECRET,
'X-Store-Id': '22',
},
});
const data = await response.json();
console.log(data);Node.js (axios)
const axios = require('axios');
const client = axios.create({
baseURL: 'https://api.selorax.io/api/apps/v1',
headers: {
'X-Client-Id': process.env.CLIENT_ID,
'X-Client-Secret': process.env.CLIENT_SECRET,
'X-Store-Id': process.env.STORE_ID,
},
});
// Fetch orders
const { data } = await client.get('/orders');
// Update a product
await client.put('/products/123', {
title: 'Updated Product Name',
price: 29.99,
});cURL
curl -X GET https://api.selorax.io/api/apps/v1/orders \
-H "X-Client-Id: sx_app_1b16e193a28d2640d2d9734dbf4907e8" \
-H "X-Client-Secret: sx_secret_dd0f155b..." \
-H "X-Store-Id: 22"Comparison: All Authentication Methods
| Method | Use Case | Expiry | Headers | Best For |
|---|---|---|---|---|
| OAuth Bearer | User-initiated actions | 24 hours | Authorization: Bearer sx_at_... | Apps acting on behalf of a logged-in merchant |
| Session Token | Iframe embedded apps | 10 minutes | Authorization: Bearer eyJ... | Embedded app UI inside the dashboard |
| Client Credentials | Server-to-server | Never | X-Client-Id + X-Client-Secret + X-Store-Id | Background jobs, webhooks, cron tasks |
Choosing the right method
- If your app has a UI embedded in the dashboard, use Session Tokens for iframe authentication and API calls from the frontend.
- If your app acts on behalf of a merchant who is actively using it, use the OAuth 2.0 flow to obtain Bearer tokens.
- If your app runs server-side without user interaction, use Client Credentials.
Many apps use a combination: session tokens for the embedded UI, and client credentials for background processing.
Rotating Secrets
If your client secret is compromised, rotate it immediately:
POST /api/apps/:app_id/rotate-secret
Requires [auth, admin] middleware and the apps__manage_apps permission.
This generates a new client_secret and invalidates the old one. All requests using the old secret will fail immediately. The new secret is returned once in the response and cannot be retrieved again.
:::danger After rotating, update the secret in all your environments (production, staging, development) before the next API call. There is no grace period -- the old secret stops working immediately. :::
Security Best Practices
- Never expose
client_secretin frontend code. Client credentials are for server-to-server use only. If you need browser-side authentication, use Session Tokens. - Use environment variables. Store
CLIENT_ID,CLIENT_SECRET, andSTORE_IDin environment variables or a secrets manager. Never hard-code them. - Restrict network access. If possible, allowlist your server's IP addresses to limit where API calls can originate from.
- Monitor usage. Watch for unexpected spikes in API calls that could indicate a leaked secret.
- Rotate periodically. Even without a known compromise, rotating secrets on a regular schedule (e.g. quarterly) reduces risk.