Skip to main content
Two Factor Authentication support is available in CoCart Plus starting from .

Prerequisites

CoCart Plus automatically detects the plugin and loads 2FA support only when available.
In the following request examples below, you would replace <username> and <password> with your credentials before sending the request.

Authentication Flow

1. Initial Login Attempt (No 2FA Code)

When a user with 2FA enabled attempts to login without providing a 2FA code:
# Store response and HTTP status code
response=$(curl -s -w "\n%{http_code}" -X POST https://your-store.com/wp-json/cocart/v2/login \
    -H "Content-Type: application/json" \
    -d '{
        "username": "<username>",
        "password": "<password>"
    }')

# Extract HTTP status code (last line) and response body
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

# Handle 2FA requirement
if [ "$http_code" = "401" ]; then
    echo "2FA required. Response:"
    echo "$body"
    # Parse JSON to extract 2FA info (requires jq)
    # available_providers=$(echo "$body" | jq -r '.data.available_providers[]')
    # default_provider=$(echo "$body" | jq -r '.data.default_provider')
fi
Response (401 Unauthorized):
{
    "code": "cocart_2fa_required",
    "message": "2FA verification required. Please provide a 2FA code using one of these providers: email, totp",
    "data": {
        "status": 401,
        "2fa_required": true,
        "available_providers": ["email", "totp"],
        "default_provider": "totp",
        "email_sent": false
    }
}
Important: If the default provider is email, an email with the verification code is automatically sent to the user’s email address, and email_sent will be true.

2. Complete Login with 2FA Code

# Complete login with 2FA code
response=$(curl -s -w "\n%{http_code}" -X POST https://your-store.com/wp-json/cocart/v2/login \
    -H "Content-Type: application/json" \
    -d '{
        "username": "user@example.com",
        "password": "password123",
        "2fa_code": "123456"
    }')

# Extract HTTP status code and response body
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

# Handle response
if [ "$http_code" = "200" ]; then
    echo "Login successful!"
    echo "$body"
    # Extract token if using JWT (requires jq)
    # token=$(echo "$body" | jq -r '.token')
else
    echo "Login failed. Response:"
    echo "$body"
fi

Option B: Specifying Provider Explicitly

# Complete login with explicit 2FA provider
response=$(curl -s -w "\n%{http_code}" -X POST https://your-store.com/wp-json/cocart/v2/login \
    -H "Content-Type: application/json" \
    -d '{
        "username": "user@example.com",
        "password": "password123",
        "2fa_code": "123456",
        "2fa_provider": "email"
    }')

# Extract HTTP status code and response body
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

# Handle response
if [ "$http_code" = "200" ]; then
    echo "Login successful!"
    echo "$body"
    # Extract token if using JWT (requires jq)
    # token=$(echo "$body" | jq -r '.token')
else
    echo "Login failed. Response:"
    echo "$body"
fi

Default Provider Logic

The default provider is determined by the following priority order:
  1. Last Successfully Used Provider: The provider the user most recently used for successful authentication (CoCart Plus tracks this automatically)
  2. User’s Primary Provider: The provider set as primary in the user’s Two Factor settings
  3. First Enabled Provider: If no primary provider is set, uses the first provider in the enabled providers list
  4. Fallback: Empty string if no providers are enabled (shouldn’t occur in practice)

Provider Memory & Smart Defaults

CoCart Plus automatically remembers which 2FA provider each user successfully used last time, making subsequent logins more convenient:

Automatic Tracking

  • When: Every successful 2FA authentication
  • What: Stores the provider alias and timestamp
  • Where: User meta keys _cocart_2fa_last_used_provider and _cocart_2fa_last_used_timestamp

Benefits

  • Faster logins: Users don’t need to specify their preferred provider each time
  • Better UX: Reduces cognitive load for users with multiple 2FA methods
  • Fail-safe: Always validates that the remembered provider is still enabled

API Parameters

2fa_code

  • Type: String
  • Required: Conditional (required only if user has 2FA enabled)
  • Description: The verification code from the user’s 2FA provider

2fa_provider

  • Type: String
  • Required: No
  • Enum: Dynamically populated from available Two Factor providers
  • Description: Specific provider to use for verification
  • Available Providers: The list includes all providers installed with the Two Factor plugin using clean aliases (e.g., email, totp, backup)

Provider-Specific Behavior

TOTP (Time-based One-Time Password)

  • Uses apps like Google Authenticator, Authy
  • Codes are 6-digit numbers that expire every 30 seconds
  • No additional setup required during login

Email

  • Sends verification codes via email
  • Automatic Email Sending: When email is the default provider and no code is provided, an email is automatically sent
  • Codes typically expire after 15 minutes
  • Response includes "email_sent": true when email is sent

Backup Codes

  • Static codes that can be used when primary method is unavailable
  • Each code can only be used once
  • Treated like any other provider in the API

Error Handling

Invalid 2FA Code

{
    "code": "cocart_2fa_invalid_code",
    "message": "Invalid 2FA code provided.",
    "data": {
        "status": 401
    }
}

Invalid Provider

{
    "code": "cocart_2fa_invalid_provider", 
    "message": "Invalid 2FA provider: invalid_provider_name",
    "data": {
        "status": 400
    }
}

Client Implementation Example

async function loginWithCoCart(username, password, twoFactorCode = null, provider = null) {
    const payload = { username, password };
    
    if (twoFactorCode) {
        payload['2fa_code'] = twoFactorCode;
    }
    
    if (provider) {
        payload['2fa_provider'] = provider;
    }

    try {
        const response = await fetch('/wp-json/cocart/v2/login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
        });

        const data = await response.json();

        if (response.status === 401 && data.data?.['2fa_required']) {
            // Handle 2FA requirement
            const defaultProvider = data.data.default_provider;
            const emailSent = data.data.email_sent;

            if (emailSent) {
                alert('Verification code sent to your email');
            }

            // Prompt user for 2FA code and retry
            const code = prompt('Enter your 2FA code:');
            return loginWithCoCart(username, password, code, defaultProvider);
        }

        if (!response.ok) {
            throw new Error(data.message);
        }

        return data; // Successful login
    } catch (error) {
        console.error('Login failed:', error);
        throw error;
    }
}

Security Considerations

  • All 2FA validation uses the Two Factor plugin’s security measures
  • Codes are validated with replay protection
  • Email codes have built-in expiration
  • Rate limiting is handled by the Two Factor plugin
  • TOTP validation accounts for clock drift
  • No 2FA codes are logged or stored by CoCart
I