---
description: Set up authentication for the B2C CLI including Account Manager API clients, OCAPI permissions, and WebDAV access keys.
---

# Authentication Setup

This guide covers setting up authentication for the B2C CLI, including Account Manager API clients, OCAPI permissions, and WebDAV access.

## Overview

The CLI uses different authentication mechanisms depending on the operation:

| Operation                                                                                          | Auth Method                  | Setup Required                                                                           |
| -------------------------------------------------------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------- |
| [Code](/cli/code) deploy, watch (file upload)                                                      | WebDAV (Basic Auth or OAuth) | [WebDAV Access](#webdav-access)                                                          |
| [Code](/cli/code) list, activate, delete                                                           | OAuth + OCAPI                | [API Client](#account-manager-api-client) + [OCAPI](#ocapi-configuration)                |
| [Jobs](/cli/jobs), [Sites](/cli/sites)                                                             | OAuth + OCAPI                | [API Client](#account-manager-api-client) + [OCAPI](#ocapi-configuration)                |
| SCAPI commands ([schemas](/cli/scapi-schemas), [custom-apis](/cli/custom-apis), [eCDN](/cli/ecdn)) | OAuth + SCAPI scopes         | [API Client](#account-manager-api-client) + [SCAPI Scopes](#scapi-authentication)        |
| [CIP analytics](/cli/cip) (`cip query`, `cip report`)                                              | OAuth + Client Credentials   | [API Client](#account-manager-api-client) + Salesforce Commerce API role + tenant filter |
| [SLAS](/cli/slas) client management                                                                | OAuth                        | None (uses built-in client) or [API Client](#account-manager-api-client)                 |
| [Sandbox](/cli/sandbox) management                                                                 | OAuth                        | None (uses built-in client) or [API Client](#account-manager-api-client)                 |
| [Account Manager](/cli/account-manager)                                                            | OAuth                        | None (uses built-in client) or [API Client](#account-manager-api-client)                 |
| [MRT](/cli/mrt) commands                                                                           | MRT API Key                  | [MRT API Key](#managed-runtime-api-key)                                                  |

::: tip Zero-Config for Platform Commands
Sandbox, SLAS, and Account Manager commands work out of the box without any client configuration. The CLI includes a built-in public client that authenticates via browser login (Authorization Code + PKCE). You only need to configure an API client if you want to use client credentials for automation/CI or need specific scopes.
:::

::: tip
Each CLI command page documents its specific authentication requirements. See the [CLI Reference](/cli/) for details.
:::

## Account Manager API Client

Most CLI operations require an Account Manager API Client. This is configured in the Salesforce Commerce Cloud Account Manager.

### Authentication Methods

The CLI supports five authentication methods:

| Method                             | When Used                                                                                      | Role Configuration                        |
| ---------------------------------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------- |
| **User Authentication**            | When `--user-auth` is passed, or when only a client ID is provided (no secret)                 | Roles configured on your **user account** |
| **Client Credentials**             | When both `--client-id` and `--client-secret` are provided                                     | Roles configured on the **API client**    |
| **JWT Bearer**                     | When `--jwt-cert` and `--jwt-key` are provided (certificate-based authentication)              | Roles configured on the **API client**    |
| **Stateful User Authentication**   | After running `b2c auth login` — browser-based login, token stored and reused                  | Roles configured on your **user account** |
| **Stateful Client Authentication** | After running `b2c auth client` — client credentials login, token stored and reused            | Roles configured on the **API client**    |

**User Authentication** opens a browser for interactive login and uses roles assigned to your user account. This is ideal for development and manual operations. Use `--user-auth` as a shorthand for `--auth-methods user` on any OAuth command — both select the Authorization Code + PKCE flow.

In dw.json, the same shorthand is available as `"user-auth": true`. It is mutually exclusive with `"auth-methods"` — set one or the other, not both.

**Client Credentials** uses the API client's secret for non-interactive authentication. This is ideal for CI/CD pipelines and automation.

**JWT Bearer** uses a public/private certificate pair for authentication without storing client secrets. See [JWT Authentication](#jwt-authentication-certificate-based) for details.

**Stateful User Auth** uses `b2c auth login` to open a browser for interactive login once (Authorization Code + PKCE). The CLI persists both the access token *and* a long-lived refresh token, so subsequent commands silently refresh expired access tokens without re-opening the browser. Clear the session with `b2c auth logout`. See [Auth Commands](/cli/auth#b2c-auth-login) for details.

**Stateful Client Auth** uses `b2c auth client` to authenticate once with client credentials (or user/password) and store the **access token** for reuse across subsequent commands. The client secret is never persisted, and there is no automatic refresh — when the access token expires, re-run `b2c auth client` with the same credentials. For refresh-capable user authentication, use `b2c auth login` instead. See [Auth Commands](/cli/auth#b2c-auth-client) for details.

After signing in with `auth login` or `auth client`, you can omit the client ID from later commands. The CLI automatically reuses the valid saved session when no other client is configured.

::: warning Stateful vs Stateless Precedence
The stored session is used only when the token is valid **and** no explicit auth flags are provided. The CLI falls back to stateless auth when:
- The stored token is **expired or invalid** — a warning suggests re-running `b2c auth client --client-id <id> --client-secret <secret>` (for client-credentials sessions) or `b2c auth login` (for user sessions).
- **Explicit stateless auth flags** are passed (`--client-secret`, `--user-auth`, or `--auth-methods`) — a warning lists the flags that triggered the override. Remove them to use the stored session. Note that `--client-id` alone does not force stateless; the stored session is used if the configured client ID matches.

To opt out of stateful auth entirely, run `b2c auth logout` to clear the stored session. The CLI will then use stateless auth exclusively.
:::

::: tip
For Account Manager operations that require user-level roles (organization and API client management), use `--user-auth` to authenticate with your user account. See [Account Manager Authentication](/cli/account-manager#authentication) for per-subtopic role requirements.
:::

### Creating an API Client

1. Log in to [Account Manager](https://account.demandware.com).
2. Navigate to **API Client** in the left menu.
3. Click **Add API Client**.
4. Fill in the required fields:
   - **Display Name**: A descriptive name (e.g., "B2C CLI")
   - **Password**: A strong client secret (save this securely for Client Credentials auth)
5. Configure the **Token Endpoint Auth Method**:
   - `client_secret_basic` for client credentials flow
   - `private_key_jwt` for JWT Bearer authentication (certificate-based)

::: info
For client credentials with secrets, use `client_secret_basic` (the default). `client_secret_post` is not currently supported.
:::

### Assigning Roles

Roles grant permission to perform specific operations. Roles are configured differently depending on your authentication method.

#### Understanding Roles and Tenant Filters

Most roles require a **tenant filter** that specifies which tenants/realms the role applies to. This is configured alongside the role assignment.

| Role                              | Operations                                | Notes                                       |
| --------------------------------- | ----------------------------------------- | ------------------------------------------- |
| `Salesforce Commerce API`         | SCAPI commands and CIP analytics commands | API clients only. Requires a tenant filter.   |
| `Sandbox API User`                | ODS management, SLAS client management    | Requires tenant filter with realm/org IDs.  |
| `SLAS Organization Administrator` | SLAS client management (user auth only)   | User accounts only. Requires a tenant filter. |

#### For Client Credentials (Roles on API Client)

Under the API Client's **Roles** section:

1. Add roles needed for your operations
2. For each role, configure the **tenant filter** with the tenant IDs (for example, `zzxy_prd`) or realm IDs you need to access

**Important:** The `Salesforce Commerce API` role is currently only available for API Clients, not user accounts.

#### For User Authentication (roles on User)

In Account Manager, navigate to your user account and add roles. Note that some operations require Client Credentials authentication.

### Configuring Scopes

Under **Default Scopes**, add the following scopes based on your needs:

| Scope          | Purpose                                                   |
| -------------- | --------------------------------------------------------- |
| `mail`         | Required for user info in authentication flows            |
| `roles`        | Critical - returns role information in the token          |
| `tenantFilter` | Critical - returns tenant access information in the token |
| `openid`       | Required for OpenID Connect                               |

For SCAPI commands, also add the relevant API scopes:

| Scope                | Commands              | Reference                           |
| -------------------- | --------------------- | ----------------------------------- |
| `sfcc.cdn-zones`     | eCDN read operations  | [eCDN Commands](/cli/ecdn)          |
| `sfcc.cdn-zones.rw`  | eCDN write operations | [eCDN Commands](/cli/ecdn)          |
| `sfcc.scapi-schemas` | SCAPI schema browsing | [SCAPI Schemas](/cli/scapi-schemas) |
| `sfcc.custom-apis`   | Custom API status     | [Custom APIs](/cli/custom-apis)     |

**Note:** Do NOT add `SALESFORCE_COMMERCE_API` as a scope. This is a role, not a scope.

See the individual CLI command pages for complete scope requirements.

### Configuring Tenant Filter

For ODS, SLAS, and SCAPI operations, your API client's roles must have a tenant filter configured:

1. In Account Manager, go to the API Client settings
2. Under each role (for example, `Salesforce Commerce API`, `Sandbox API User`), find the **Tenant Filter**
3. Add the tenant IDs (for example, `zzxy_prd`) or organization IDs you need to access

The tenant filter restricts which tenants/realms the role applies to.

### Redirect URLs

For **User Authentication** (Authorization Code + PKCE), configure redirect URLs in your API client:

| Redirect URL                                                         | Purpose                                                   |
| -------------------------------------------------------------------- | --------------------------------------------------------- |
| `http://localhost:8080`                                              | Required for B2C CLI user authentication                  |
| `https://admin.dx.commercecloud.salesforce.com/oauth2-redirect.html` | Optional - enables ODS Swagger interface with same client |

**Note:** Redirect URLs are not required for API clients using only Client Credentials or JWT Bearer authentication.

**Use a public client.** The Authorization Code + PKCE flow requires the API client to be registered in Account Manager as a **public client** (not a confidential client). Public clients have no secret and selecting that type configures the Authorization Code + PKCE grant automatically. A client's type can't be changed after creation, so a legacy implicit-only client must be replaced by a newly-created public client, not converted. See [Implicit Flow Deprecation (PKCE Migration)](#implicit-flow-deprecation) for the transitional fallback behavior and how to resolve the deprecation warning.

::: tip Running Behind a Proxy
If you're running the CLI behind a proxy where `localhost:8080` isn't reachable by the browser, set `SFCC_REDIRECT_URI` to the proxy URL (e.g., `https://proxy.example.com:8080`). The proxy should forward traffic to the CLI's local server. You can also change the local server port with `SFCC_OAUTH_LOCAL_PORT`. Make sure to add your proxy URL to the API client's redirect URLs in Account Manager.
:::

## JWT Authentication (Certificate-Based)

JWT Bearer authentication (RFC 7523) is an alternative to client secrets that uses public/private certificate pairs. This can be useful in environments where you want to avoid storing client secrets.

### How It Works

1. You generate a certificate pair (public certificate + private key)
2. You register the **public certificate** in Account Manager
3. The CLI uses the **private key** to sign JWT tokens for authentication
4. Account Manager verifies the signature using your registered certificate

### Benefits

- **No client secret required**: Authenticate without storing a client secret
- **Rotation**: Certificates can be rotated without updating secrets across pipelines
- **Industry standard**: Implements OAuth 2.0 JWT Bearer (RFC 7523)

### Setup Instructions

#### Step 1: Generate Certificate Pair

Generate an RSA certificate pair using OpenSSL:

```bash
openssl req -x509 -newkey rsa:4096 \
  -keyout key.pem \
  -out cert.pem \
  -days 365 \
  -nodes \
  -subj "/CN=B2C CLI"
```

This creates two files:
- `cert.pem` - Public certificate (upload to Account Manager)
- `key.pem` - Private key (keep secure on your machine)

::: tip Encrypted Keys
For additional security, generate an encrypted private key by omitting `-nodes` and adding a passphrase when prompted. You'll provide the passphrase via `--jwt-passphrase` when using the CLI.
:::

#### Step 2: Register Certificate in Account Manager

1. Log in to [Account Manager](https://account.demandware.com)
2. Navigate to **API Client** and select your client
3. Set **Token Endpoint Auth Method** to `private_key_jwt`
4. Upload `cert.pem` in the **Certificates** section
5. Save changes

::: tip Multiple Certificates per Client
You can register **multiple certificates** for the same API client. This is useful for:
- **Team collaboration**: Each developer generates their own key pair and registers their certificate
- **Key rotation**: Add a new certificate before removing the old one (zero downtime)
- **Multi-environment**: Different certificates for CI/CD, staging, production

Account Manager will verify JWT signatures against all registered certificates, so each team member can authenticate with their own private key while sharing the same client ID.
:::

#### Step 3: Configure CLI

You can provide JWT credentials via CLI flags, environment variables, or configuration files.

**Using CLI flags:**

```bash
b2c code list \
  --client-id your-client-id \
  --jwt-cert ./cert.pem \
  --jwt-key ./key.pem
```

**Using environment variables:**

```bash
export SFCC_CLIENT_ID=your-client-id
export SFCC_JWT_CERT=/path/to/cert.pem
export SFCC_JWT_KEY=/path/to/key.pem

b2c code list
```

**Using dw.json:**

```json
{
  "hostname": "your-instance.demandware.net",
  "client-id": "your-client-id",
  "jwt-cert-path": "./cert.pem",
  "jwt-key-path": "./key.pem"
}
```

**For encrypted keys:**

```bash
b2c code list \
  --client-id your-client-id \
  --jwt-cert ./cert.pem \
  --jwt-key ./key.pem \
  --jwt-passphrase "your-passphrase"

# Or via environment variable
export SFCC_JWT_PASSPHRASE=your-passphrase
```

### Authentication Priority

JWT authentication is tried **after** client credentials (if client secret is available) but **before** the user (browser) flow:

1. `client-credentials` - Uses client secret if available
2. `jwt` - Uses JWT certificate if configured (no client secret)
3. `user` - Opens browser for Authorization Code + PKCE login

The legacy `implicit` flow has been removed from the default chain. It is still selectable via `--auth-methods implicit` for backwards compatibility, but emits a deprecation warning; OAuth 2.1 deprecates implicit for public clients.

To force JWT authentication even when a client secret is configured:

```bash
b2c code list --auth-methods jwt
```

### Troubleshooting

**"JWT certificate file not found"**
- Verify the certificate path is correct
- Use absolute paths or paths relative to current directory

**"Invalid JWT private key"**
- Check that the key file is in PEM format
- If encrypted, ensure you provide the correct passphrase via `--jwt-passphrase`

**"JWT authentication failed (401)"**
- Verify the certificate is registered in Account Manager
- Ensure the Token Endpoint Auth Method is set to `private_key_jwt`
- Check that the client ID matches the API client with the registered certificate

**"Invalid certificate format"**
- The certificate must be in PEM format (starts with `-----BEGIN CERTIFICATE-----`)
- Regenerate the certificate using the OpenSSL command above

### Security Best Practices

- **Keep private keys secure**: Never commit `key.pem` to version control
- **Add to .gitignore**: Include `*.pem` and `*.key` in your `.gitignore`
- **Use encrypted keys in production**: Generate keys with passphrases for production use
- **Rotate certificates regularly**: Generate new certificates periodically (every 90-365 days)
- **Store passphrases securely**: Use secret managers for passphrases in CI/CD

## OCAPI Configuration

For operations that interact with B2C Commerce instances (code deployment, jobs, sites), you need to configure OCAPI permissions on each instance.

### Configuring OCAPI in Business Manager

1. Log in to Business Manager
2. Navigate to **Administration** > **Site Development** > **Open Commerce API Settings**
3. Select the **Data API** type
4. Add a configuration for your client ID

### Example OCAPI Configuration

```json
{
  "_v": "24.5",
  "clients": [
    {
      "client_id": "your-client-id",
      "resources": [
        {
          "resource_id": "/code_versions",
          "methods": ["get"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        },
        {
          "resource_id": "/code_versions/*",
          "methods": ["get", "put", "patch", "delete"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        },
        {
          "resource_id": "/jobs/*/executions",
          "methods": ["post"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        },
        {
          "resource_id": "/jobs/*/executions/*",
          "methods": ["get"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        },
        {
          "resource_id": "/job_execution_search",
          "methods": ["post"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        },
        {
          "resource_id": "/sites",
          "methods": ["get"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        },
        {
          "resource_id": "/sites/*",
          "methods": ["get"],
          "read_attributes": "(**)",
          "write_attributes": "(**)"
        }
      ]
    }
  ]
}
```

### Minimal Configuration by Feature

**Code management only:**

```json
{
  "resource_id": "/code_versions",
  "methods": ["get"]
},
{
  "resource_id": "/code_versions/*",
  "methods": ["get", "put", "patch", "delete"]
}
```

**Job execution only:**

```json
{
  "resource_id": "/jobs/*/executions",
  "methods": ["post"]
},
{
  "resource_id": "/jobs/*/executions/*",
  "methods": ["get"]
},
{
  "resource_id": "/job_execution_search",
  "methods": ["post"]
}
```

**Site listing only:**

```json
{
  "resource_id": "/sites",
  "methods": ["get"]
},
{
  "resource_id": "/sites/*",
  "methods": ["get"]
}
```

**BM administration (`bm roles`, `bm users`, `bm whoami`, `bm access-key`):**

```json
{
  "resource_id": "/roles",
  "methods": ["get"]
},
{
  "resource_id": "/roles/*",
  "methods": ["get", "put", "delete"]
},
{
  "resource_id": "/roles/*/users",
  "methods": ["get"]
},
{
  "resource_id": "/roles/*/users/*",
  "methods": ["put", "delete"]
},
{
  "resource_id": "/roles/*/permissions",
  "methods": ["get", "put"]
},
{
  "resource_id": "/users",
  "methods": ["get"]
},
{
  "resource_id": "/users/*",
  "methods": ["get", "patch", "delete"]
},
{
  "resource_id": "/users/this",
  "methods": ["get"]
},
{
  "resource_id": "/users/*/access_key/*",
  "methods": ["get", "put", "patch", "delete"]
},
{
  "resource_id": "/user_search",
  "methods": ["post"]
}
```

::: tip BM functional permissions
`bm whoami` and the `bm access-key` family additionally require *a real BM user identity*. Service-client tokens cannot resolve to a BM user, so the CLI defaults these commands to browser-based user auth. Access-key writes also require the **Manage_Users_Access_Keys** BM functional permission on the user account performing the request — grant it via **Administration** > **Roles & Permissions** in Business Manager. See [BM Commands → Authentication](/cli/bm#authentication) for details.
:::

## SCAPI Authentication

SCAPI commands (eCDN, SCAPI schemas, custom APIs) require OAuth authentication with specific roles and scopes.

### Required Setup

1. **Role:** Assign the `Salesforce Commerce API` role to your API client with appropriate tenant filter
2. **Scopes:** Add required SCAPI scopes to your API client's Default Scopes

### Scopes by Command

| Command                       | Required Scope       | Reference                           |
| ----------------------------- | -------------------- | ----------------------------------- |
| `b2c scapi schemas list/get`  | `sfcc.scapi-schemas` | [SCAPI Schemas](/cli/scapi-schemas) |
| `b2c scapi custom status`     | `sfcc.custom-apis`   | [Custom APIs](/cli/custom-apis)     |
| `b2c ecdn` (read operations)  | `sfcc.cdn-zones`     | [eCDN](/cli/ecdn)                   |
| `b2c ecdn` (write operations) | `sfcc.cdn-zones.rw`  | [eCDN](/cli/ecdn)                   |

The CLI automatically requests these scopes. Your API client must have them in the Default Scopes list.

::: tip
For detailed authentication requirements including specific scopes for each command, see the individual [CLI command reference pages](/cli/).
:::

### Configuration

```bash
# Set credentials
export SFCC_CLIENT_ID=my-client
export SFCC_CLIENT_SECRET=my-secret
export SFCC_TENANT_ID=zzxy_prd
export SFCC_SHORTCODE=kv7kzm78

# Example: List SCAPI schemas
b2c scapi schemas list
```

## WebDAV Access

WebDAV is required for file upload operations (`code deploy`, `code watch`, `webdav` commands). There are two ways to authenticate, depending on who (or what) is connecting:

- **Basic Authentication** — for individual developers using their own Business Manager account during interactive, local development.
- **OAuth** — for API clients and automation (CI/CD pipelines, scripts) where no human is logging in.

### Option A: Basic Authentication (user access)

Use your Business Manager username and a WebDAV access key. This is the simplest option for interactive, user-based access during local development.

1. In Business Manager, go to **Administration** > **Organization** > **Users**
2. Select your user
3. Generate or view your **WebDAV Access Key**

See [Configure WebDAV File Access](https://help.salesforce.com/s/articleView?id=cc.b2c_account_manager_sso_use_webdav_file_access.htm&type=5) for detailed instructions.

```bash
export SFCC_USERNAME=your-bm-username
export SFCC_PASSWORD=your-webdav-access-key
```

### Option B: OAuth-based WebDAV (API client access)

For API clients and automation (CI/CD), use OAuth credentials instead of a user's basic auth. This requires configuring WebDAV Client Permissions for the API client:

1. Log in to Business Manager
2. Navigate to **Administration** > **Organization** > **WebDAV Client Permissions**
3. Add a JSON configuration for your API client ID:

```json
{
  "clients": [
    {
      "client_id": "your-client-id",
      "permissions": [
        {"path": "/cartridges", "operations": ["read_write"]},
        {"path": "/impex", "operations": ["read_write"]},
        {"path": "/logs", "operations": ["read_write"]}
      ]
    }
  ]
}
```

Common paths for CLI operations:

| Path                      | Operations             |
| ------------------------- | ---------------------- |
| `/cartridges`             | Code deployment        |
| `/impex`                  | Site import/export     |
| `/logs`                   | Log file access        |
| `/catalogs/<catalog-id>`  | Catalog file access    |
| `/libraries/<library-id>` | Content library access |

**Note:** This configuration is only needed when using OAuth for WebDAV. It isn’t required when using basic authentication with username/access key.

## Managed Runtime API Key

MRT commands use a separate API key system.

### Getting an MRT API Key

1. Log in to the [Managed Runtime dashboard](https://runtime.commercecloud.com/)
2. Navigate to **Account Settings** > **API Keys**
3. Click **Create API Key**
4. Copy and save the key securely (it's only shown once)

### Configuring the API Key

```bash
# Save credentials to ~/.mobify
b2c mrt save-credentials --user your-email@example.com --api-key your-mrt-api-key

# Or use an environment variable
export MRT_API_KEY=your-mrt-api-key
```

## Quick Start Example

Here's a complete example for setting up CLI access:

### 1. Create API Client in Account Manager

1. Log in to [Account Manager](https://account.demandware.com)
2. Navigate to **API Client** > **Add API Client**
3. Configure:
   - **Display Name**: `B2C CLI`
   - **Password**: Generate a strong secret (save securely)
   - **Roles**:
     - `Salesforce Commerce API` - add tenant filter with your tenant IDs
     - `Sandbox API User` - if using ODS (add tenant filter)
   - **Default Scopes**: `mail roles tenantFilter openid sfcc.cdn-zones`
   - **Redirect URLs**: `http://localhost:8080` (for user authentication)

### 2. Configure OCAPI (for code list/activate/delete, jobs, sites)

Add the JSON configuration shown in [OCAPI Configuration](#ocapi-configuration) to enable code version and job APIs.

### 3. Configure WebDAV Access (for code deploy/watch, webdav commands)

Either:

- Use your BM username + WebDAV access key (for user-based, interactive development), or
- Configure WebDAV Client Permissions for OAuth (for API clients and CI/CD)

### 4. Set Environment Variables

```bash
# OAuth credentials
export SFCC_CLIENT_ID=your-client-id
export SFCC_CLIENT_SECRET=your-client-secret

# Instance (for OCAPI commands)
export SFCC_SERVER=your-instance.demandware.net

# SCAPI (for eCDN, schemas, custom-apis)
export SFCC_TENANT_ID=zzxy_prd
export SFCC_SHORTCODE=kv7kzm78

# WebDAV (if using BM credentials)
export SFCC_USERNAME=your-bm-username
export SFCC_PASSWORD=your-webdav-access-key
```

### 5. Test the Configuration

```bash
# Test OAuth + OCAPI
b2c code list

# Test WebDAV
b2c webdav ls --root=cartridges

# Test SCAPI
b2c scapi schemas list
```

## Troubleshooting

### "Unauthorized" errors

- Verify your client ID and secret are correct
- Check that OCAPI is configured for your client ID
- Ensure the API client has the required roles

### "Forbidden" on WebDAV operations

- Check WebDAV Client Permissions in Business Manager
- Verify your WebDAV access key is correct
- Ensure the folder you're accessing is permitted

### "Invalid scope" errors

- Add the required scopes to your API client's Default Scopes
- For SCAPI commands, ensure the relevant `sfcc.*` scopes are in Default Scopes
- Verify that Default Scopes includes `mail roles tenantFilter openid`

## Implicit Flow Deprecation (PKCE Migration) {#implicit-flow-deprecation}

The browser-based `user` authentication method now uses the **Authorization Code flow with PKCE** (Proof Key for Code Exchange). The legacy **implicit** flow is deprecated for public clients per OAuth 2.1 and is no longer the default. Most users are unaffected — this section is for those with a legacy implicit-only client seeing a deprecation warning.

### What changed

- `b2c auth login` and the `user` auth method use Authorization Code + PKCE by default and persist a **refresh token**, so subsequent commands refresh silently without re-opening the browser.
- The implicit flow is still selectable for backward compatibility via `--auth-methods implicit` (or `"auth-methods": ["implicit"]` in `dw.json`), but it emits a deprecation warning and cannot obtain refresh tokens.

### You must use a public client

PKCE requires the Account Manager client to be a **public client**. Selecting that type in Account Manager configures the Authorization Code + PKCE grant automatically and the client has no secret.

**An Account Manager client's type cannot be changed after it is created.** A legacy implicit-only client therefore has to be **replaced by a newly-created public client** — it cannot be converted in place. Create a new public client, add the CLI's redirect URI (`http://localhost:8080` by default), and use its client ID.

### Transitional automatic fallback

To keep existing users working during the migration, if the configured client is **not** a PKCE-capable public client, the `user` flow automatically falls back to the deprecated implicit flow for that client and logs a warning:

```
[Auth] Authorization Code + PKCE failed for client <id> (<oauth error>). Falling back to
the deprecated implicit flow. Recommend creating a new public (PKCE) client in Account
Manager and using it to remove this warning.
```

The fallback triggers **only** for OAuth errors that indicate the client is not a public/PKCE client — `invalid_client` (Account Manager requires client authentication at the token exchange; the most common case for legacy implicit clients), `unauthorized_client`, `unsupported_response_type`, and `unsupported_grant_type`. Other failures (for example `invalid_scope` from requesting scopes the client can't have, or a cancelled login) surface directly without falling back, because they would fail identically under the implicit flow.

The first fallback can require two browser authorization prompts while the tooling switches to the compatible flow. After a successful fallback, later CLI and VS Code sign-ins use that flow directly and avoid the extra prompt. The first browser callback reports that authorization was received instead of reporting a successful sign-in before the fallback completes.

To resolve the warning, create a new public client as described above and use its client ID. To disable the fallback entirely and surface PKCE failures directly, set `SFCC_DISABLE_PKCE_FALLBACK=1`. The fallback is temporary and will be removed once public clients have migrated.

## Next Steps

- [Configuration](./configuration) - Learn how configuration is shared across the CLI, MCP server, and VS Code extension
- [CLI Reference](/cli/) - Browse available commands
