# Authentication

All API requests must be authenticated. To get authorized, you must include a valid access token in the **Authorization** header:

```http
Authorization: Bearer your-access-token
```

To get a valid access token you need to send a `POST` request to the following endpoint:

```http
https://auth.commercelayer.io/oauth/token
```

The payload to be sent with the request differs based on the kind of [API credentials](https://docs.commercelayer.io/core/api-credentials) you want to use to authenticate and will be detailed case by case in the following sections.

{% hint style="info" %}
Please note that the authentication endpoint is subject to a [rate limit](https://docs.commercelayer.io/core/rate-limits) of **max 30 reqs / 1 min** both in live and test mode.
{% endhint %}

{% hint style="success" %}
Check our [JS Auth](https://github.com/commercelayer/commercelayer-js-auth), a TypeScript library wrapper that helps you use Commerce Layer API for authentication, providing also some useful helper methods (e.g. [access token decoding](https://github.com/commercelayer/commercelayer-js-auth?tab=readme-ov-file#decode-an-access-token) and [verification](https://github.com/commercelayer/commercelayer-js-auth?tab=readme-ov-file#verify-an-access-token)).
{% endhint %}

### Authorization grant flows

To get an access token, you need to execute an authorization flow by using valid API credentials for the client.

The authorization flow depends on the [grant type](https://oauth.net/2/grant-types/) as described in the table below:

<table><thead><tr><th>Grant type</th><th data-type="checkbox">Sales channel</th><th data-type="checkbox">Integration</th><th data-type="checkbox">Webapp</th></tr></thead><tbody><tr><td><strong>Client credentials</strong></td><td>true</td><td>true</td><td>false</td></tr><tr><td><strong>Password</strong></td><td>true</td><td>false</td><td>false</td></tr><tr><td><strong>Authorization code</strong></td><td>false</td><td>false</td><td>true</td></tr><tr><td><strong>Refresh token</strong></td><td>true</td><td>false</td><td>true</td></tr><tr><td><strong>JWT bearer</strong></td><td>true</td><td>false</td><td>true</td></tr></tbody></table>

{% hint style="warning" %}
As a general rule, *non-confidential* (public) API credentials (e.g. **sales channels**) can authenticate (requesting and revoking access tokens, using refresh tokens) using just a client ID, without providing a client secret and can be safely used client-side. *Confidential* (private) API credentials (e.g. **integrations**, **webapps**) need a client secret to authenticate.
{% endhint %}

### Access token expiry

For security reasons, access tokens expire after a default period of time. Your access token lifetime differs based on the kind of API credentials you're using:

| API client                                                                           | Default lifetime |
| ------------------------------------------------------------------------------------ | ---------------- |
| [Sales channel](https://docs.commercelayer.io/core/client-credentials#sales-channel) | **4 hours**      |
| [Integration](https://docs.commercelayer.io/core/client-credentials#integration)     | **2 hours**      |
| [Webapp](https://docs.commercelayer.io/core/authorization-code#webapp)               | **2 hours**      |

You can specify a custom lifetime for the token at the API credentials level on the admin Dashboard when you create/update each of them or set it via our [Provisioning API](https://app.gitbook.com/s/xrdVVavnnBMHRCqrLp1y/api-reference/api_credentials#access-token-expiry). The token lifetime value must be expressed **in seconds** and fall within a **min** of **2 hours** (**7200 secs**) and a **max** of **15 days** (**1296000 secs**).

A new token is issued **15 mins** (**900 secs**) before the previous token's expiration date. During that overlap time window, both the new and the old token are valid, thus helping you [optimize your auth token caching strategy](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/faq/authentication-and-access-tokens#i-keep-being-rate-limited-on-auth-calls.-what-shall-i-do) and avoid asking for a new token every time you make a call.

{% hint style="info" %}
[Refresh tokens](https://docs.commercelayer.io/core/authentication/refresh-token) have a fixed default lifetime of **2 weeks** that cannot be modified.
{% endhint %}

{% hint style="warning" %}
To avoid security issues, be careful not to set too long expiration dates for your access tokens.
{% endhint %}

### Authorization scopes

For each of the above authorization flows you can restrict the scope to a specific [market](#putting-a-market-in-scope), [store](#putting-a-store-in-scope), and/or [stock location](#putting-a-stock-location-in-scope).

The access token scope is a string that can be composed in two ways:

* by **ID** — `{{resource_name}}:id:{{resource_id}}`

  \
  Where `{{resource_name}}` can be one of `market`, `store`, or `stock_location`, and `{{resource_id}}` is the `id` of the resource (e.g. `market:id:xYZkjABcde`, `store:id:bGvCXzYgNB`, `stock_location:id:WLgbSXqyoZ`).\\
* by **code** — `{{resource_name}}:code:{{resource_code}}`

  \
  Where `{{resource_name}}` can be one of `market`, `store`, or `stock_location`, and `{{resource_code}}` is the `code` of the resource (e.g. `market:code:europe`, `store:code:outlet_ny`, `stock_location:code:eu_warehouse`).

{% hint style="info" %}
Defining a market, store, or stock location code and using it for your scope(s) can come in handy to replicate your setup when switching from *Test* to *Live* mode which are two different, separate [environments](https://docs.commercelayer.io/core/api-specification#environments) where corresponding resources would have different IDs.
{% endhint %}

{% hint style="warning" %}
Using authorization scopes with [integration](https://docs.commercelayer.io/core/api-credentials#integration) API credentials works only if associated with a **custom role**. The results of calls performed with integration API credentials associated with *admin* or *read-only* roles are not filtered, even if a scope was specified when requesting the token.
{% endhint %}

#### Putting a market in scope

By including a market scope in the access token request — `market:id:xYZkjABcde` — all the resources (e.g. SKUs, prices, stock items) you fetch are automatically filtered.

<pre class="language-json"><code class="lang-json">{
  "grant_type": "{{authorization_grant}}",
  "client_id": "{{your_client_id}}",
  ...,
<strong>  "scope": "market:id:xYZkjABcde"
</strong>}
</code></pre>

{% hint style="warning" %}
The market in scope must be *active* (i.e. enabled). [Disabled markets](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/markets#disabling-markets) are excluded from any authorization scope recalculation.
{% endhint %}

{% hint style="info" %}
When [fetching a collection of SKUs](https://docs.commercelayer.io/core/fetching-resources#fetching-a-collection-of-skus) with a market in scope only the SKUs that are *sellable* in that market are returned. To be sellable in a market an SKU must have a price in the market's price list and at least one stock item in one of the market's stock locations, **regardless of its quantity**.
{% endhint %}

{% hint style="warning" %}
**Sales channels** require a market in scope when requesting their access tokens to perform the [permitted CRUD actions](https://docs.commercelayer.io/core/roles-and-permissions#sales-channel). If the market in scope is associated with a customer group, it becomes private and can be accessed only by the customers belonging to the group — in that case, to get your token you must use the [password flow](https://docs.commercelayer.io/core/authentication/password).
{% endhint %}

#### Putting a store in scope

By including a store scope in the access token request — `store:id:bGvCXzYgNB` — all the resources (e.g. SKUs, prices) you fetch are automatically filtered by the market the store is associated with, orders are associated with the store in scope, and the returned available payment methods are the store's ones (if any, otherwise the associated market ones). When calculating the stock availability, the associated market stock locations hierarchy is extended by adding the store's stock location (if any) as the one with the highest priority and increasing by 1 the inventory model's stock locations cutoff value.

<pre class="language-json"><code class="lang-json">{
  "grant_type": "{{authorization_grant}}",
  "client_id": "{{your_client_id}}",
  ...,
<strong>  "scope": "store:id:bGvCXzYgNB"
</strong>}
</code></pre>

{% hint style="warning" %}
When putting a store in scope, there's no need to specify the associated market, which is inherited from the store itself. Only **one** store in scope is allowed, if you put multiple store in scope the API responds with a `400 Bad Request` error code.
{% endhint %}

#### Putting a stock location in scope

By including a stock location scope in the access token request — `stock_location:id:WLgbSXqyoZ` — the stock is restricted to the SKUs available in that specific stock location.

<pre class="language-json"><code class="lang-json">{
  "grant_type": "{{authorization_grant}}",
  "client_id": "{{your_client_id}}",
  ...,
<strong>  "scope": "market:id:xYZkjABcde stock_location:id:WLgbSXqyoZ"
</strong>}
</code></pre>

{% hint style="warning" %}
When putting a stock location in scope, adding the associated market in the access token request is **mandatory**. If the market scope is missing or the stock location doesn't belong to the market in scope the API responds with a `400 Bad Request` error code.
{% endhint %}
