HTTP API authorization
Authorization methods and principles used to access the commercetools Composable Commerce HTTP APIs.
The Composable Commerce HTTP API uses OAuth 2.0 to authorize requests to the API.
Learn more about Composable Commerce OAuth 2.0 for API authentication in our self-paced Authorization flows and API Clients module.
Creating an API Client
You can either use the Merchant Center or the API Clients endpoint to create an API Client.
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 the Composable Commerce OAuth 2.0 service
To request an access token from the Composable Commerce OAuth 2.0 service, use the following hosts:
Region | Auth URL |
---|---|
North America (Google Cloud, Iowa) | https://auth.us-central1.gcp.commercetools.com/ |
North America (AWS, Ohio) | https://auth.us-east-2.aws.commercetools.com/ |
North America (Azure, Virginia) | https://auth.eastus.azure.commercetools.com/ |
Europe (Google Cloud, Belgium) | https://auth.europe-west1.gcp.commercetools.com/ |
Europe (AWS, Frankfurt) | https://auth.eu-central-1.aws.commercetools.com/ |
Europe (Azure, Frankfurt) | https://auth.germanywestcentral.azure.commercetools.com/ |
Australia (Google Cloud, Sydney) | https://auth.australia-southeast1.gcp.commercetools.com/ |
Although the deprecated hostnames like auth.sphere.io
(Google Cloud, Belgium) and auth.commercetools.co
(Google Cloud, Iowa) remain intact as aliases we strongly encourage changing your configuration to the new host name structure.
The Authorization API provides the following Authorization flows:
- Client credentials: Creates a token for an API Client.
- Password flow: Creates a token using the customers 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.
Authentication can also be handled using one of the commercetools SDKs. If you are familiar with Postman, you can also use commercetools Postman Collections to create code snippets for authenticating to the API.
Client credentials flow
To obtain an access token through the client credentials flow, just
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://{auth_host}/oauth/tokenAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Content-Type: application/x-www-form-urlencodedgrant_type=client_credentials&scope={scope}
Example request
$curl https://{auth_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
media 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.
Password flow for global Customers
POST https://{auth_host}/oauth/{projectKey}/customers/tokenAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Content-Type: application/x-www-form-urlencodedgrant_type=password&username={email}&password={password}&scope={scope}
Password flow for Customers in a Store
POST https://{auth_host}/oauth/{projectKey}/in-store/key={storeKey}/customers/tokenAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Content-Type: application/x-www-form-urlencodedgrant_type=password&username={email}&password={password}&scope={scope}
Example request
$curl https://{auth_host}/oauth/{projectKey}/customers/token -X POST \--basic --user "{clientId}:{clientSecret}" \-d "grant_type=password&username=alice@example.com&password=secret&scope=view_published_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey}"
Example response
{"access_token": "v-dZ10ZCpvbGfwcFniXqfkAj0vq1yZVI","expires_in": 172800, // seconds (2 days)"scope": "view_published_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} customer:{id}","refresh_token": "{projectKey}: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://{auth_host}/oauth/tokenAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Content-Type: application/x-www-form-urlencodedgrant_type=refresh_token&refresh_token={token}
By default, refresh tokens expire 200 days after last usage or if the limit of 10 million
refresh tokens is exceeded (in the latter case, the least recently used tokens expire first). Therefore a refresh token that is frequently 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 to 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}
parameter.
POST https://{auth_host}/oauth/{projectKey}/anonymous/tokenAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==Content-Type: application/x-www-form-urlencodedgrant_type=client_credentials&scope={scope}
Example request
$curl https://{auth_host}/oauth/{projectKey}/anonymous/token -X POST \--basic --user "{clientId}:{clientSecret}" \-d "grant_type=client_credentials&scope=view_published_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey}&anonymous_id={uniqueId}"
Example response
{"access_token": "v-dZ10ZCpvbGfwcFniXqfkAj0vq1yZVI","expires_in": 172800, // seconds (2 days)"scope": "view_published_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} anonymous_id={uniqueId}","refresh_token": "{projectKey}:OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U","token_type": "Bearer"}
Introspection
The authorization service also implements OAuth 2.0 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.
Example request
$curl https://{auth_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, // Unix epoch (Thu Jul 27 2017 12:33:20 GMT+0000)"client_id": "tl-zzoobQGyBbFhqccWB_ZiK"}
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 (for example 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
To use OAuth 2.0 Bearer tokens issued by another service, provide an RFC 7662-compliant OAuth 2.0 Token Introspection endpoint to your Project using the Set ExternalOAuth update action.
The Composable Commerce Authorization API calls the endpoint provided to verify the validity of the token, and check the token's scopes. The API only accepts its own scopes. Any scopes which are not listed in the Scopes section are ignored.
Some services, especially OpenID Connect implementations, may already provide such an endpoint and may allow embedding permissions specific to Composable Commerce into the scope. In other cases, you may have to implement a service specifically to verify the token or create the scope.
A Project using tokens issued by an external OAuth service can continue to use tokens issued by Composable Commerce. The APIs validate the tokens against the respective introspection endpoints with no additional configuration required. The API might cache External OAuth tokens for up to 30 minutes to improve response times.
Please note that using External OAuth tokens affects performance. 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.
Headers
When calling the introspection endpoint of an external OAuth server, in addition to the Authorization
header, the request will also contain a correlation ID if there is one available:
X-Correlation-ID
- A correlation ID can be used to track a request. The same correlation ID will be returned to the original caller of the API.
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 you want the API to use. For example, you can use HTTP Basic Authentication by saving a header like Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
. You can also use OAuth 2.0 Bearer tokens, and refresh the used token on a regular basis 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 Composable Commerce should, for performance reasons, not be done during the token verification. Ideally, the customer accounts are created before a token for the customer is issued to be used with the Composable Commerce APIs.
Limits and error cases
The External OAuth token introspection affects the performance and uptime of commercetools Composable Commerce. 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 Region your Project is running on and your introspection endpoint is as low as possible.
Time limits
If the introspection is not responding fast, the whole API call is blocked. We therefore enforce the following limits:
- The introspection endpoint must return a result within
500 ms
to the Authorization API. This includes the network latency between the two.
We recommend that your introspection endpoint returns results much more faster, though. A good target is to respond within less than 50 ms.
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.
The following errors codes are returned when the introspection endpoint does not respond successfully:
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/introspectHost: example.orgContent-Type: application/x-www-form-urlencodedAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==token={token}
If your endpoint responds with the following, the API request will succeed:
HTTP/1.1 200 OKContent-Type: application/json{"active": true,"scope": "view_published_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 OKContent-Type: application/json{"active": false}
HTTP/1.1 200 OKContent-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 OKContent-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 OAuth 2.0 service returns an access_token
.
Use the access token in the Authorization
header of all requests to commercetools Composable Commerce as follows:
POST /{{projectKey}}/channels HTTP/1.1Host: api.{region}.commercetools.comAuthorization: Bearer {accesstoken}...
commercetools Composable Commerce does not support sending access tokens as URI parameters, as defined in RFC 6750 section 2.3.
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 then refresh the token at a regular interval. In this approach, all instances of your application use the same token. In most of the 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.
Create anonymous sessions only once necessary
At first sight, creating a new token with a new anonymous session on the first request is the most straight forward implementation. However, this pattern results in a very high number of unused anonymous sessions, for example if a stateless web crawler acts like a new visitor on every request or if visitors drop off after only browsing the site.
To avoid creating unused anonymous sessions, hold a visitor-independent client credentials flow token (for example with only the view_published_products
scope) and only request a token with an anonymous session when the visitor creates a cart, shopping list or other visitor-specific resource. A single API Client can be used to create both types of tokens.
Note that the number of refresh tokens is limited to 10 million
. If the limit is exceeded, the least recently used refresh tokens are deleted. Creating new refresh tokens continues to work.
Revoking tokens
The Composable Commerce authorization service implements Auth 2.0 Token Revocation under /oauth/token/revoke
. This endpoint provides a mechanism to invalidate access and refresh tokens within the authorization server. For example, when a customer logs out, changes identity, or uninstalls your application, you might want to revoke the tokens associated with the customer. This behavior prevents the abuse of abandoned tokens and can contribute to a better customer experience.
Only tokens that were issued to the client making the revocation request are allowed to be revoked by the client. To revoke a token, it is necessary to provide the token, and optionally a type hint. The type hint can either be refresh_token
or access_token
. Parameters are provided using the application/x-www-form-urlencoded
media type.
Example request
$curl https://{auth_host}/oauth/token/revoke -X POST \--basic --user "{clientId}:{clientSecret}" \-d "token={token}&token_type_hint={access_token|refresh_token}"
Response
The endpoint will only provide a status code for the response:
200
- the token was found and revoked, or the token request was invalid.5xx
- in case of a server error, the client has to assume that the token still exists, and should retry after a reasonable delay.