---
title: Install version 8
slug: commerce-connect-15/service-api/install-version-8
docTags: 
createdAt: 2026-08-04T09:43:11.000Z
---

Service API version 8 is compatible with Optimizely Commerce Connect 15 and ships in the `EPiServer.ServiceApi.Commerce` package. Version 8 replaces the OpenID Connect authentication used in [versions 6 and 7](docId\:N-6GmOMNLnHgn3NZ_3KRJ) with a built-in JSON Web Token (JWT) bearer token flow. The Service API issues and validates the tokens, so no external identity provider is required.

For Service API 6 or 7, see [Install versions 6 and 7](docId\:N-6GmOMNLnHgn3NZ_3KRJ). This page applies to Service API 8 and Commerce Connect 15 only.

## What changed in version 8

The following table compares authentication between the versions.

| Area                   | Versions 6 and 7                                           | Version 8                                                 |
| ---------------------- | ---------------------------------------------------------- | --------------------------------------------------------- |
| Authentication package | `EPiServer.OpenIDConnect`                                  | Built into `EPiServer.ServiceApi`, so no separate package |
| Token type             | OAuth 2 bearer token issued by OpenID Connect              | JWT bearer token issued by the Service API                |
| Token endpoint         | `/api/episerver/connect/token`                             | `/episerverapi/auth/login`                                |
| Grant types            | `client_credentials` in version 6, `password` in version 7 | Username and password login, with refresh tokens          |
| Refresh tokens         | Not supported                                              | Supported, with optional rotation and revocation          |

## Prerequisites

Complete the following before you install Service API 8.

- Install Optimizely Commerce Connect 15.
- [Install Optimizely updates](docId\:VuiU-K4aAR6ISGicFg4lk) through the NuGet Package Manager in Visual Studio.

## Install Service API

1. Open your solution in Visual Studio.
2. Select **Tools > NuGet Package Manager > Manage NuGet Packages for Solution**.
3. Click **Settings** to create a source that points to the Optimizely NuGet feed.
4. Open the **Browse** tab and select the source you created.
5. Install [EPiServer.ServiceApi](https://nuget.optimizely.com/package/?id=EPiServer.ServiceApi) and [EPiServer.ServiceApi.Commerce](https://nuget.optimizely.com/package/?id=EPiServer.ServiceApi.Commerce) version 8 or later.

Version 8 does not require the `EPiServer.OpenIDConnect` package. The Service API provides JWT authentication.

## Configure authentication

### Add the authentication settings

Add a `ServiceApi:Authentication` section to `appsettings.json`.

```json
{
  "ServiceApi": {
    "Authentication": {
      "SigningKey": "A_STRONG_SECRET_SIGNING_KEY",
      "Authority": "https://mysite.com",
      "Audience": "epi_service_api",
      "RequireHttpsMetadata": true
    }
  }
}
```

The section supports the following settings.

- `SigningKey` – The symmetric secret that signs and validates JWT access tokens with HMAC-SHA256. Use a long, random value and store it securely.
- `Authority` – The token issuer. Set it to the site URL that issues tokens.
- `Audience` – The audience, or scope, that tokens are issued for. Defaults to the Service API scope, `epi_service_api`, when omitted.
- `RequireHttpsMetadata` – Whether HTTPS is required for authentication metadata. Set it to `true` for production.

Keep the `SigningKey` out of source control. Store it in user secrets, environment variables, or a secret store, and rotate it if it is exposed.

### Register the Service API

Register the Service API and its authentication in `Startup.cs` or `Program.cs`. The following extension method registers the credential validator, token service, refresh token store, and JWT bearer authentication.

```csharp
public static IServiceCollection AddCommerceServiceApi(
    this IServiceCollection services, IConfiguration configuration)
{
    services.AddTransient<PermissionService, AllowAllPermissionService>();
    services.AddSingleton<ServiceApiTokenService>();
    services.TryAddSingleton<IRefreshTokenStore, InMemoryRefreshTokenStore>();
    services.AddScoped<IServiceApiCredentialValidator, DefaultServiceApiCredentialValidator<SiteUser>>();

    var serviceApiAuth = configuration.GetSection("ServiceApi:Authentication");
    services.AddServiceApiAuthentication(jwt =>
    {
        jwt.SigningKey = serviceApiAuth["SigningKey"];
        jwt.Authority = serviceApiAuth["Authority"];
        jwt.Audience = serviceApiAuth["Audience"] ?? ServiceApiOptionsDefaults.Scope;
        jwt.RequireHttpsMetadata = bool.TryParse(serviceApiAuth["RequireHttpsMetadata"], out var https) && https;
    });

    return services;
}
```

Call the extension method during service registration.

```csharp
services.AddCommerceServiceApi(configuration);
```

`AllowAllPermissionService` grants all permissions and is intended for evaluation only. In production, use a permission service that enforces the read and write access defined in Permissions for functions.

### Customize credential validation and token storage

The default implementation validates credentials against ASP.NET Identity through `UserManager` and stores refresh tokens in memory. Replace either implementation by registering a custom type before you call `AddCommerceServiceApi`.

| Interface                        | Default implementation                           | Purpose                                                                                                           |
| -------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `IServiceApiCredentialValidator` | `DefaultServiceApiCredentialValidator<SiteUser>` | Validates a username and password and builds the claims principal used to issue tokens. Supports account lockout. |
| `IRefreshTokenStore`             | `InMemoryRefreshTokenStore`                      | Stores, retrieves, revokes, and expires refresh tokens.                                                           |

:::hint{type="info"}
**Note**
`InMemoryRefreshTokenStore` does not persist tokens across restarts or share them across instances. For load-balanced or production environments, implement `IRefreshTokenStore` against a shared, durable store, such as a database.
:::

### Configure token options

`ServiceApiAuthOptions` controls access and refresh token behavior.

- `AccessTokenLifetime` – How long an access token is valid. Returned to clients as `expires_in`, in seconds.
- `RefreshTokenLifetime` – How long a refresh token is valid.
- `RotateRefreshTokens` – When `true`, each refresh issues a new refresh token and revokes the previous one. When `false`, the same refresh token works until it expires.

## Authentication endpoints

Service API 8 exposes JWT authentication endpoints under `episerverapi/auth`. All requests and responses use JSON.

### Log in

Exchange a username and password for an access token and a refresh token.

```http
POST /episerverapi/auth/login HTTP/1.1
Host: mysite.com
Content-Type: application/json

{
  "username": "admin",
  "password": "your-password"
}
```

A successful request returns `200 OK`.

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "3Qh8s0Zr...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

The endpoint returns the following status codes.

- `200 OK` – Returns the access and refresh tokens.
- `401 Unauthorized` – The username or password is incorrect (`invalid_credentials`).
- `423 Locked` – The account is locked because of multiple failed login attempts (`account_locked`).

Error responses use the following shape.

```json
{
  "error": "invalid_credentials",
  "error_description": "The username or password is incorrect."
}
```

The following cURL command logs in and returns a token pair.

```bash
curl --location --request POST 'https://mysite.com/episerverapi/auth/login' \
  --header 'Content-Type: application/json' \
  --data-raw '{ "username": "admin", "password": "your-password" }'
```

### Refresh a token

Exchange a valid refresh token for a new access token. When `RotateRefreshTokens` is enabled, the response also returns a new refresh token and revokes the previous one.

```http
POST /episerverapi/auth/refresh HTTP/1.1
Host: mysite.com
Content-Type: application/json

{
  "refresh_token": "3Qh8s0Zr..."
}
```

The endpoint returns the following status codes.

- `200 OK` – Returns a new access token and refresh token.
- `401 Unauthorized` – The refresh token is invalid, expired, or revoked (`invalid_token`).

### Log out

Revoke a refresh token. This endpoint requires a valid access token.

```http
POST /episerverapi/auth/logout HTTP/1.1
Host: mysite.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "refresh_token": "3Qh8s0Zr..."
}
```

The endpoint returns the following status codes.

- `204 No Content` – The refresh token is revoked.
- `401 Unauthorized` – The request is not authenticated.

## Send a request with the token

Include the access token as a bearer token in the `Authorization` header of every Service API call. The following example imports a catalog.

```csharp
using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("https://mysite.com/");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    var content = new MultipartFormDataContent();
    var filestream = new FileStream(path, FileMode.Open);
    content.Add(new StreamContent(filestream), "file", "Catalog.zip");

    var response = client.PostAsync("/episerverapi/commerce/import/catalog", content).Result;
    if (response.StatusCode == HttpStatusCode.OK)
    {
        var returnString = response.Content.ReadAsStringAsync().Result;
        returnString = returnString.Replace("\"", "");
        Guid taskId = Guid.Empty;
        Guid.TryParse(returnString, out taskId);
    }
}
```

## Access token claims

The access token is a JWT signed with `SigningKey` using HMAC-SHA256. It includes the following claims, which the Service API uses for authorization.

- `jti` – A unique token identifier.
- `scope` – The audience the token is issued for.
- `sub` and `nameidentifier` – The authenticated user's ID.
- `name` – The user name.
- `email` – The user's email address, when available.
- `role` – One claim per role assigned to the user. Used to enforce read and write access.

## Refresh token behavior

Refresh tokens extend a session without resending the user's credentials. The Service API handles them as follows.

- Refresh tokens are random values. The store keeps only a SHA-256 hash of each token, never the raw value.
- A refresh token is valid until it expires, based on `RefreshTokenLifetime`, or until the logout endpoint or token rotation revokes it.
- When `RotateRefreshTokens` is enabled, each refresh issues a new refresh token and revokes the previous one, so each refresh token is valid for a single use.
- When the user tied to a refresh token is no longer valid or is locked out, the Service API rejects and revokes the token.

## Permissions for functions

The Service API enforces authorization for read and write operations through **Permissions for Functions**, based on the `role` claims in the access token.

1. Go to **Admin > Access Rights > Permissions for Functions**.
2. Select **ReadAccess** or **WriteAccess** under **EPiServerServiceApi**, depending on the permission you want to grant.
3. Add the user or role that is present in the authenticated token's claims.

For example, to allow reading or updating the catalog, grant access to the `/episerverapi/commerce/export/catalog/` and `/episerverapi/commerce/import/catalog/` endpoints. Confirm the claim identity has the correct roles for read and write access to the Permissions for Functions for the Service API.

## Strongly typed catalog content types

Strongly typed catalog content types must be present in the context of a Service API site. When you install the Service API to an existing website, the site resolves this automatically. When you install the Service API as a standalone application, deploy the assembly that contains the strongly typed catalog content types, and any dependencies of that assembly, to the Service API `bin` folder.

## Troubleshoot Service API

Address the following issues when you set up the Service API.

- Confirm the server has a valid certificate from a trusted certificate authority for the site.
- Confirm all Service API requests use HTTPS.
- When tokens are rejected with a signature error, confirm the `SigningKey` matches between the issuing and validating configuration and has not changed since the token was issued.
- When refresh tokens stop working after a restart or on a load-balanced site, replace the default in-memory refresh token store with a persistent `IRefreshTokenStore` implementation.

The Service API has no rate limit.

See also [Service API REST API reference](https://docs.developers.optimizely.com/commerce/v1.3.0-service-api-developer-guide/reference/service-api-reference-guides).
