Authentication
Request, use, and renew OAuth tokens without mixing applications and API keys.
Auth issues OAuth 2.0 tokens. Protected endpoints receive the
token in Authorization; public endpoints do not need one. Check the security
section for each operation in the reference.
Application credentials
An OAuth application created in the dashboard provides a client_id and
client_secret. The secret identifies a server, so it must not reach a browser
or a distributed application.
An API key created with POST /v1/api-keys belongs to the UCP service, whose
reference is not published yet.
It cannot be used at /connect/token, and no Admin,
Storefront, or Auth operation accepts
it.
Use the Bearer token shown by each operation for those APIs.
Token for an Admin integration
Use client_credentials and include the api_admin scope:
curl -X POST https://auth.ecomiq.pe/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$ECOMIQ_CLIENT_ID" \
-d "client_secret=$ECOMIQ_CLIENT_SECRET" \
-d "scope=api_admin"{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6...",
"token_type": "Bearer",
"expires_in": 3600
}expires_in is the lifetime in seconds for that response. Calculate expiration
from this value instead of assuming a fixed duration.
Use the token
curl "https://api.ecomiq.pe/api/v1/catalog/products?limit=25" \
-H "Authorization: Bearer $ECOMIQ_TOKEN"Admin also needs store context and, when applicable, seller context. In the public workflow documented here, that context comes from token claims. See Context and hierarchy.
Grants
| Grant | Use |
|---|---|
client_credentials | A server acts as the application. It requires a confidential client and does not create a user session. |
authorization_code | A user signs in and authorizes an application configured for this flow. |
refresh_token | Renews a session when the application and issued token support this grant. |
password | Only explicitly configured first-party clients. Do not use it for third-party integrations. |
The application defines which grants and scopes it accepts. Do not send a grant only because it appears in this table.
Renewal
client_credentials does not need a refresh token: request another access token
before the current one expires. Cache the token per process and use a short
margin to avoid sending it while it expires.
let cached: { token: string; expiresAt: number } | undefined;
export async function getToken(): Promise<string> {
if (cached && Date.now() < cached.expiresAt - 60_000) {
return cached.token;
}
const body = new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.ECOMIQ_CLIENT_ID!,
client_secret: process.env.ECOMIQ_CLIENT_SECRET!,
scope: "api_admin",
});
const response = await fetch("https://auth.ecomiq.pe/connect/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
if (!response.ok) throw new Error(`OAuth HTTP ${response.status}`);
const payload = await response.json();
cached = {
token: payload.access_token,
expiresAt: Date.now() + payload.expires_in * 1000,
};
return cached.token;
}Coordinate renewal if several processes share credentials. This prevents a burst of simultaneous token requests.
Authentication failures
401means the endpoint did not receive a valid credential.403means the identity was accepted, but a policy, scope, permission, or context blocked the operation./connect/tokenreturns OAuth errors such asinvalid_clientorinvalid_grant; do not assume it uses Problem Details or acodefield.
Do not log the token, secret, or complete body of an OAuth response.