CoCart supports multiple authentication methods depending on the use case.
No authentication is needed for guest cart operations. The SDK automatically manages the cart session for you:
- First request — No cart key exists yet. The CoCart server creates a new guest session and returns a
Cart-Keyheader in the response. - SDK extracts it — The SDK reads the
Cart-Keyheader and stores it on the client instance automatically. - Subsequent requests within the same script — The stored cart key is sent as both a
Cart-Keyheader and acart_keyquery parameter, so the server knows which cart to use.
$client = new CoCart('https://your-store.com');
// First page load — add item, cart key is persisted to PHP session automatically
$client->cart()->addItem(123, 2);
echo $client->getCartKey(); // 'guest_abc123...'
// Next page load — cart key is restored from PHP session automatically
$client = new CoCart('https://your-store.com');
$cart = $client->cart()->get(); // Same cart as beforeThe SDK uses PHP sessions ($_SESSION) behind the scenes to persist and restore the cart key. No extra setup is needed.
In CLI scripts or test environments where PHP sessions are not available, disable auto-storage:
$client = new CoCart('https://your-store.com', ['auto_storage' => false]);For multi-store setups, use separate session keys to avoid collisions:
$clientA = new CoCart('https://store-a.com', ['session_key' => 'store_a_cart']);
$clientB = new CoCart('https://store-b.com', ['session_key' => 'store_b_cart']);If you already have a cart key (e.g. stored in your own database), pass it directly. This takes priority over any value in the session:
$client = new CoCart('https://your-store.com', [
'cart_key' => 'existing_cart_key',
]);For authenticated customers using WordPress username/password:
$client = new CoCart('https://your-store.com', [
'username' => 'customer@email.com',
'password' => 'customer_password',
]);
// Or set at runtime
$client = new CoCart('https://your-store.com');
$client->setAuth('customer@email.com', 'password');
// Check auth status
$client->isAuthenticated(); // true
$client->isGuest(); // falseIf the CoCart JWT Authentication plugin (v3.0+) is installed, login() acquires JWT tokens automatically. If the plugin is not installed, login() throws an AuthenticationException. For stores without JWT, use Basic Auth directly via setAuth().
$client = new CoCart('https://your-store.com');
// Login — acquires JWT tokens (requires CoCart JWT Authentication plugin)
$response = $client->login('customer@email.com', 'password');
echo $response->get('display_name'); // 'john'
echo $response->get('user_id'); // '123'
// Subsequent requests automatically use the acquired credentials
$cart = $client->cart()->get();$client->logout(); // Calls server logout endpoint, then clears local JWT and refresh tokens$client->jwt()->refresh();if ($client->jwt()->validate()) {
echo 'Token is valid';
} else {
echo 'Token is expired or invalid';
}Check if the token is expired locally without making an API call:
// Check if expired (with 30-second leeway by default)
if ($client->jwt()->isTokenExpired()) {
$client->jwt()->refresh();
}
// Custom leeway (e.g., refresh 5 minutes before expiry)
if ($client->jwt()->isTokenExpired(300)) {
$client->jwt()->refresh();
}
// Get the expiry timestamp
$expiry = $client->jwt()->getTokenExpiry();
if ($expiry !== null) {
echo 'Token expires at: ' . date('Y-m-d H:i:s', $expiry);
}Expired tokens are automatically refreshed and retried. This is enabled by default when using $client->login(). If you set a JWT token manually, you can enable it explicitly:
$client->setJwtToken('eyJ...');
$client->setRefreshToken('refresh_hash_...');
$client->jwt()->setAutoRefresh(true);
// Expired tokens are refreshed and retried automatically
$cart = $client->cart()->get();Pass a storage adapter to the JWT Manager for automatic persistence between page loads:
use CoCart\JwtManager;
use CoCart\Storage\PhpSessionStorage;
$storage = new PhpSessionStorage();
$jwt = new JwtManager($client, $storage);
$client->setJwtManager($jwt);
// Tokens are saved to storage after login/refresh
$client->login('user@example.com', 'password');
// On subsequent page loads, tokens are restored automatically
$client2 = new CoCart('https://your-store.com');
$jwt2 = new JwtManager($client2, $storage);
$client2->setJwtManager($jwt2);
// $client2 now has the stored JWT token — no need to login again$client->jwt()->hasTokens(); // true if a JWT token is set
$client->jwt()->isTokenExpired(); // true if token is expired (local check)
$client->jwt()->getTokenExpiry(); // unix timestamp of token expiry
$client->jwt()->isAutoRefreshEnabled(); // check auto-refresh status
$client->jwt()->setAutoRefresh(true); // enable/disable at runtimeIf the WordPress Two Factor plugin is installed and a user has 2FA enabled, the server returns a 401 challenge response on the first login attempt instead of tokens. CoCart Plus v1.6.0+ and CoCart Community v4.8+ are required.
The SDK surfaces this as a TwoFactorRequiredException, which you catch and handle before completing login with the OTP code.
use CoCart\Exceptions\TwoFactorRequiredException;
$client = new CoCart('https://your-store.com');
try {
$response = $client->login('customer@email.com', 'password');
// No 2FA required — login complete
} catch (TwoFactorRequiredException $e) {
// Prompt the user for their code, then complete login
$code = $_POST['2fa_code']; // e.g. '123456'
$response = $client->loginWith2fa('customer@email.com', 'password', $code);
}
echo $response->get('display_name'); // 'john'The exception carries metadata from the server about which 2FA providers are available:
} catch (TwoFactorRequiredException $e) {
$providers = $e->getAvailableProviders(); // ['email', 'totp']
$default = $e->getDefaultProvider(); // 'totp'
$emailSent = $e->isEmailSent(); // true if email code was auto-sent
// Ask the user which provider to use, then:
$response = $client->loginWith2fa('customer@email.com', 'password', $code, 'email');
}Pass the provider name as the fourth argument to loginWith2fa(). If omitted, the server uses its default:
// TOTP (authenticator app)
$client->loginWith2fa($username, $password, $totpCode, 'totp');
// Email
$client->loginWith2fa($username, $password, $emailCode, 'email');
// Backup code
$client->loginWith2fa($username, $password, $backupCode, 'backup-codes');
// Let server decide (uses last-used or primary provider)
$client->loginWith2fa($username, $password, $code);If you are using SessionManager and want to merge a guest cart after login:
use CoCart\Exceptions\TwoFactorRequiredException;
try {
$response = $session->loginWithJwt($username, $password);
} catch (TwoFactorRequiredException $e) {
$response = $session->loginWithJwt2fa($username, $password, $code);
// Guest cart is merged automatically
}| Provider | Value | Notes |
|---|---|---|
| TOTP | 'totp' |
Authenticator apps (Google Authenticator, Authy). 6-digit code, 30-second window. |
'email' |
Code sent via email. When email is the default provider, the code is sent automatically on the first login attempt (isEmailSent() returns true). |
|
| Backup Codes | 'backup-codes' |
Single-use static codes for account recovery. |
For admin-only endpoints like Sessions API, use WooCommerce REST API credentials:
$client = new CoCart('https://your-store.com', [
'consumer_key' => 'ck_xxxxx',
'consumer_secret' => 'cs_xxxxx',
]);
$sessions = $client->sessions()->all();When multiple auth credentials are configured, the SDK uses this priority:
- JWT Token (
jwt_token) — Bearer token - Basic Auth (
username/password) — Basic auth header - Consumer Keys (
consumer_key/consumer_secret) — Basic auth header
// Start with JWT
$client = new CoCart('https://your-store.com', [
'jwt_token' => 'eyJ...',
]);
// Switch to Basic Auth (clears JWT)
$client->setAuth('user', 'pass');
// Switch to JWT (clears Basic Auth)
$client->setJwtToken('new.jwt.token');
// Clear everything
$client->clearSession();If your WordPress site uses a custom REST URL prefix (via rest_url_prefix filter) or CoCart has been white-labelled with a different namespace:
// Custom REST prefix (site uses /api/ instead of /wp-json/)
$client = new CoCart('https://your-store.com', [
'rest_prefix' => 'api',
]);
// Requests go to: https://your-store.com/api/cocart/v2/cart
// White-labelled namespace
$client = new CoCart('https://your-store.com', [
'namespace' => 'mystore',
]);
// Requests go to: https://your-store.com/wp-json/mystore/v2/cart
// Both together
$client = new CoCart('https://your-store.com', [
'rest_prefix' => 'api',
'namespace' => 'mystore',
]);
// Requests go to: https://your-store.com/api/mystore/v2/cart
// Or set at runtime
$client->setRestPrefix('api')->setNamespace('mystore');JWT endpoints also respect the namespace automatically:
// Refresh calls: {rest_prefix}/{namespace}/jwt/refresh-token
// Validate calls: {rest_prefix}/{namespace}/jwt/validate-tokenSome hosting providers or reverse proxies (Cloudflare, Nginx, Apache) strip or block the standard Authorization header. You can configure the SDK to use an alternative header name:
// Via constructor
$client = new CoCart('https://your-store.com', [
'username' => 'customer@email.com',
'password' => 'password',
'auth_header' => 'X-Authorization',
]);
// Or at runtime
$client->setAuthHeader('X-Authorization');The SDK will send credentials using the custom header instead:
X-Authorization: Basic dXNlcjpwYXNz
X-Authorization: Bearer eyJ...Your WordPress server must be configured to read the custom header. For example, in .htaccess:
RewriteEngine On
RewriteCond %{HTTP:X-Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:X-Authorization}]Type-hint your classes against CoCartInterface for easy mocking:
use CoCart\CoCartInterface;
class MyCartService
{
public function __construct(
private CoCartInterface $client
) {}
public function addProduct(int $productId, int $quantity): void
{
$this->client->cart()->addItem($productId, $quantity);
}
}In your tests:
use CoCart\CoCartInterface;
use CoCart\Response;
use PHPUnit\Framework\TestCase;
class MyServiceTest extends TestCase
{
public function testAddToCart(): void
{
$client = $this->createMock(CoCartInterface::class);
$response = new Response(200, [], '{"items_count": 1}');
$client->method('cart')->willReturn(/* your cart mock */);
$service = new MyCartService($client);
$service->addProduct(123, 2);
}
}