HTTP API - Authorization

Authorization methods and principles used to access the commercetools platform HTTP APIs.

The commercetools HTTP API uses ↗ OAuth2 to authorize requests to the platform.

Authorization overview

To authorize your application:

  1. Decide scope(s) for the client.
  2. Create an API Client.
  3. Request an access token using an authorization flow.
  4. (If you received a refresh token in 2.) Request further access tokens using the refresh token flow.

You can request an access token using commercetools’ OAuth2 server or an external OAuth server. Unless you are certain you need to use an external OAuth server, use the commercetools OAuth2 server.

Creating an API Client

You can either use the Merchant Center or the API Clients endpoint to create an API Client.

Note You can only use the API Clients endpoints from an authorized API Client. You must create your first API Client using the Merchant Center.

Requesting an access token using commercetools’ OAuth2 server

To request an access token from commercetools’ OAuth2 service, use one of the following hosts with one of the authorization flows below:

  • Europe: https://auth.sphere.io/
  • United States: https://auth.commercetools.co/

The commercetools platform provides the following Authorization flows:

  • Client credentials: Creates a token for API Client to make requests to the commercetools platform.
  • Password flow: Creates a token using the customers’s login credentials. This is used with /me endpoints for operations scoped to a specific user session.
  • Anonymous session flow: Creates a token for an anonymous session (a customer which might, at some point, log in or sign up.) This is used with /me endpoints for operations scoped to a specific session, or guest checkout scenarios.
  • Refresh token flow: Refreshes an access token.

We maintain a Git repository of code samples of how to authenticate to our API in various languages on ↗ Hello API Github repository .

Client Credentials Flow

To obtain an access token through the client credentials flow, simply issue the following request to the auth service, providing your client_id and client_secret via ↗ HTTP Basic Authentication , where the username is the client_id and the password is the client_secret:

POST https://{host}/oauth/token
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope={scope}

Example Request

$curl https://{host}/oauth/token -X POST \
--basic --user "{clientId}:{clientSecret}" \
-d "grant_type=client_credentials&scope=manage_project:{projectKey}"

Example Response

{
"access_token": "vkFuQ6oTwj8_Ye4eiRSsqMeqLYNeQRJi",
"expires_in": 172800, // seconds (2 days)
"scope": "manage_project:{projectKey}",
"token_type": "Bearer"
}

Parameters are provided using the application/x-www-form-urlencoded content type. The scope parameter is optional, but recommended.

Password Flow

To obtain an access token through the password flow, you need to provide the email and unencrypted password of the customer in addition to your OAuth client credentials.

POST https://{host}/oauth/{projectKey}/customers/token
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: application/x-www-form-urlencoded
grant_type=password&username={email}&password={password}&scope={scope}

Example Request

$curl https://{host}/oauth/{projectKey}/customers/token -X POST \
--basic --user "{clientId}:{clientSecret}" \
-d "grant_type=password&username=alice@example.org&password=secret&scope=view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey}"

Example Response

{
"access_token": "v-dZ10ZCpvbGfwcFniXqfkAj0vq1yZVI",
"expires_in": 172800,
"scope": "view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} customer:{id}",
"refresh_token": "OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U",
"token_type": "Bearer"
}

In addition to the access token, a refresh token is issued. The refresh token may be used to get a new access token without supplying email and password if the access token has expired.

Refresh Token Flow

To obtain an access token through the refresh token flow, you need to provide the OAuth client credentials as well as the refresh token.

POST https://{host}/oauth/token
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token={token}

Refresh tokens expire 6 months after last usage. Therefore a refresh token that is regularly used will never expire.

Tokens for Anonymous Sessions

To obtain an access token for an Anonymous Session, the OAuth client needs the create_anonymous_token scope. The regular Client Credentials Flow is used.

These access tokens are similar to those issued with the Password Flow, but they are not associated with a customer but with an anonymousId. In addition to the access token, a refresh token is issued. The refresh token is the only way to get a new access token for this particular anonymousId.

The anonymousId is either generated by the API or an unused ID can be supplied by adding the anonymous_id:{id} scope.

POST https://{host}/oauth/{projectKey}/anonymous/token
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&scope={scope}

Example Request

$curl https://{host}/oauth/{projectKey}/anonymous/token -X POST \
--basic --user "{clientId}:{clientSecret}" \
-d "grant_type=client_credentials&scope=view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} anonymous_id:{uniqueId}"

Example Response

{
"access_token": "v-dZ10ZCpvbGfwcFniXqfkAj0vq1yZVI",
"expires_in": 172800,
"scope": "view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} anonymous_id:{uniqueId}",
"refresh_token": "OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U",
"token_type": "Bearer"
}

Introspection

The commercetools authorization service also implements ↗ OAuth2 Token Introspection available under /oauth/introspect. It allows to determine the active state of an OAuth 2.0 access token and to determine meta-information about this access token, such as the scope.

Like the other endpoints, it is protected by client authentication. A client can always introspect its own access tokens. A client with introspect_oauth_tokens:{projectKey} permission (also implied by manage_project) can introspect any access token in that project, even if it was issued to a different client. If the requesting client does not have permission to introspect the given token, it is treated as not active and no further information is returned.

This endpoint can only introspect tokens issued by the commercetools auth service. External OAuth tokens have to be introspected at the external service.

Example Request

$curl https://{host}/oauth/introspect -X POST \
--basic --user "{clientId}:{clientSecret}" \
-d "token=nbzLp_xTvAmPJnilFuZGaiukILpuaCxQ"

Example Response (Active)

{
"active": true,
"scope": "view_products:example-project-26",
"exp": 1501158800852
}

Example Response (Inactive)

{
"active": false
}

If active is true, the access token can currently be used with the API, within the scope. The exp timestamp indicates when this token will expire.

You may cache the result, but consider that a token can not only expire, but also be revoked earlier (e.g. if the client that issued the token is deleted). The RFC 7662, Section 4 summarizes the tradeoff in the second-last paragraph.

Requesting an access token using an external OAuth server beta

To use OAuth2 Bearer tokens issued by another service, provide a RFC 7662-compliant ↗ OAuth2 Token Introspection endpoint to your project using the Set ExternalOAuth update action.

The commercetools platform calls the endpoint provided to verify the validity of the token, and check the token’s scopes. The commercetools platform only recognizes its own scopes: any scopes which are not listed in the Scopes section are ignored.

Some services, particularly OpenID Connect implementations, may already provide such an endpoint and may allow you to embed the commercetools permissions into the scope. In other cases, you may have to implement your own service to verify the token or create the scope.

Please note that using External OAuth tokens affects the performance of the commercetools platform: If the token introspection fails, the whole API call fails. If the introspection takes 200 ms to return a result, the whole API call takes 200 ms longer.

The commercetools platform may cache External OAuth tokens until the token expires (given by the exp field in the introspection response) for a maximum of an hour.

Note: Access tokens issued by external services do not currently work with Machine Learning endpoints.

Securing the OAuth introspection endpoint

As specified in RFC 7662, the OAuth introspection endpoint must not be publicly accessible. You have to configure the Authorization Header that the commercetools platform will use. For example, you can use ↗ HTTP Basic Authentication by saving a header like Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==. You can also use OAuth2 Bearer tokens, and regularly refresh the used token by updating the project configuration.

Handling permissions for customer accounts or anonymous sessions

If you want to use external OAuth tokens with the /me endpoints, you’ll have to add an already existing customer account, or an anonymous session, into the scope. For a customer account, add customer_id:{id}, for an anonymous session, add anonymous_id:{id} to the scope.

The synchronization of customer accounts between the external service and the commercetools platform should, for performance reasons, not be done during the token verification. Ideally, the customer accounts have been created before a token for the customer to be used with the commercetools platform is issued.

Limits and Error Cases

The External OAuth token introspection affects the performance and uptime of the commercetools platform. Therefore, you should carefully consider the technology used to implement the introspection, and your hosting options.

Independently of the technology choice you should make sure that the network latency between the commercetools platform region your project is running on and your introspection endpoint is as low as possible.

Time limits

If the introspection is not responding quickly, the whole API call is blocked. We therefore enforce the following limits:

  • The introspection endpoint must return a result within 500 ms to the commercetools platform. This includes the network latency between the two.

We recommend that your introspection endpoint returns results much more quickly, though. A good target is to respond within less than 50ms.

Error Cases

In any error case (no response within the time limit or a bad response like a 500 HTTP status code) the API call fails. The introspection is not retried within an API call. Further API calls will try to reach the introspection endpoint again.

If the introspection endpoint did not respond within the time limit, or no connection could be established, a 504 Gateway Timeout HTTP status code and the error code ExternalOAuthFailed is returned to the API caller.

If the introspection endpoint did respond, but the response couldn’t be parsed successfully (e.g. a 500 HTTP status code, or an invalid JSON object), a 502 Bad Gateway HTTP status code and the error code ExternalOAuthFailed is returned to the API caller.

Examples

Assuming you have configured the URL https://example.org/oauth/introspect and the Authorization Header Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==, and you make a request to /{projectKey}/products, your endpoint will receive the following request:

POST /oauth/introspect
Host: example.org
Content-Type: application/x-www-form-urlencoded
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

token={token}

If your endpoint responds with the following, the API request will succeed:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "active": true,
  "scope": "view_my_products:{projectKey}"
}

If your endpoint responds with one of the following, the API request will not succeed, either because the token is invalid, or because the client does not have the permission to view products:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "active": false
}
HTTP/1.1 200 OK
Content-Type: application/json

{
  "active": true,
  "scope": "view_orders:{projectKey}"
}

The following example shows a response for a token that can be used with the /me endpoints:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "active": true,
  "scope": "view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} customer_id:{id}"
}

Using an access token

Upon successful completion of an authorization flow, the OAuth2 service returns an access_token.

Use the access token in the Authorization header of all requests to the commercetools platform as follows:

POST //channels HTTP/1.1
Host: api.sphere.io
Authorization: Bearer {accesstoken}
...

The remaining lifetime of an access token is indicated by its expires_in field.

Managing token requests

For security reasons, we advise requesting tokens sparingly and keeping the number of active tokens to a minimum whenever possible.

We do not recommend requesting a token for every work item. If a client application requests too many tokens, it might be rate-limited.

We recommend getting new tokens when appropriate using automatic token management. Our SDK clients provide support for automatic token management, or you can implement token management yourself.

Short-lived applications

In some scenarios, your SDK clients are short-lived. For example, a script triggered by a cron job which creates a client every time the job runs, or a function in a serverless Function-as-a-Service environment.

We recommend the following approaches when working with short-lived client applications to reduce the number of tokens requested.

One approach is to store a token in the filesystem, a cache, or the application’s configuration. You can the refresh the token at a regular interval. In this approach, all instances of your application use the same token. In most of our SDKs, an existing token can be passed to the client. For example, in the following SDKs:

In a serverless FaaS environment, you should be able to use the global execution context to store your client across warm invocations (when the FaaS re-uses a function instance and it is not subject to a cold-start). Here is an example for an AWS Lambda function that uses the execution context.