Skip to content

Client Management

M2M OAuth clients are the foundation of programmatic API access. This guide covers creating, listing, and revoking clients through both the web interface and API endpoints.

Each M2M client represents a single integration or application that needs API access. Clients are isolated and can have different scope grants, making it easy to manage permissions per integration.

PropertyDescriptionExample
Client IDUnique 26-character identifierabc123xyz456def789ghi012
Client SecretSecure credential (shown once)qwertyuiop...
Client NameHuman-readable nameWooCommerce Integration
DescriptionPurpose of the clientProduction WooCommerce sync
ScopesGranted permissions["products.read", "brands.read"]
StatusActive or revokedactive
Created AtCreation timestamp2025-11-25T10:30:00Z
Created ByAdmin who created itadmin@example.com
Expires AtOptional expiration2026-11-25T10:30:00Z
Last Used AtLast token exchange2025-11-25T14:22:31Z
Usage CountTotal API calls made1247
  1. Navigate to Settings

    • Log in as an admin user
    • Go to Settings → API Access
  2. Click “Create M2M Client”

    • Opens the creation dialog
  3. Fill in Details

    • Client Name: Descriptive name (3-100 characters, alphanumeric, spaces, hyphens, underscores)
    • Description: Optional purpose description (max 500 characters)
    • Scopes: Select required permissions (at least one required)
    • Expiration: Optional expiration (1-365 days from now)
  4. Create and Save Credentials

    • Click “Create Client”
    • ⚠️ CRITICAL: Copy the clientId and clientSecret immediately
    • The secret is NEVER shown again
    • Store credentials securely (password manager, secrets vault)

Endpoint: POST /oauth/clients

Authentication: Requires Admin group membership (Cognito ID token)

Request:

Terminal window
curl -X POST https://{api-base-url}/oauth/clients \
-H "Authorization: Bearer YOUR_ADMIN_ID_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clientName": "WooCommerce Integration",
"description": "Production WooCommerce catalog sync",
"scopes": ["products.read", "brands.read"],
"expiresInDays": 365
}'

Response (201 Created):

{
"clientId": "abc123xyz456def789ghi012",
"clientSecret": "very-long-secure-secret-string-never-shown-again",
"clientName": "WooCommerce Integration",
"description": "Production WooCommerce catalog sync",
"scopes": ["products.read", "brands.read"],
"status": "active",
"createdAt": "2025-11-25T10:30:00Z",
"createdBy": { "userId": "a1b2c3d4-...", "userName": "Jane Smith" },
"expiresAt": "2026-11-25T10:30:00Z",
"tokenEndpoint": "{token-endpoint}",
"warning": "Store this secret securely. It cannot be retrieved later."
}
  • Required
  • Length: 3-100 characters
  • Format: Alphanumeric, spaces, hyphens, underscores
  • Pattern: ^[a-zA-Z0-9\s\-_]+$
  • Examples:
    • ✅ WooCommerce Integration
    • ✅ Analytics_Dashboard_v2
    • ✅ Mobile-App-Production
    • ❌ My@Client (special characters not allowed)
    • ❌ AB (too short)
  • Optional
  • Max Length: 500 characters
  • Format: Free text
  • Required: At least one scope
  • The complete grantable set is four scopes:
    • products.read
    • products.write
    • brands.read
    • brands.write
  • Accepted but not usable from an M2M token:
    • products.write, brands.write — write operations require an admin web-app session; an M2M token gets 403 even when it holds the scope.
  • Rejected outright by this endpoint’s validation (not grantable at all):
    • clients.read, clients.write — clients is not an M2M resource. There is no external consumer of customer data via this API.
    • quotes.read, quotes.write — the Quotes domain is part of the web application, not the M2M API.
  • Format: Array of strings (without the crm-api/ prefix; Cognito adds the resource-server identifier)
  • Case-Sensitive: Must match exactly

For an external M2M integration, grant only products.read and/or brands.read — the write scopes exist for completeness but don’t unlock a usable M2M capability. clients.* and quotes.* are not accepted values at all; requesting them returns a validation error.

Field visibility: Granting products.read (or brands.read) does not expose internal data. M2M read responses are projected through a server-side field allowlist regardless of scope — any field not on the allowlist is never returned to an M2M token, and there is no broader scope that unlocks it. (supplierCost is on the allowlist — see below.) See Troubleshooting: A field I expect is missing from the response for the complete field list.

  • Optional
  • Range: 1-365 days from creation
  • Format: Integer (days)
  • Behavior: After expiration, tokens cannot be issued (client effectively revoked)
  1. Navigate to Settings → API Access
  2. View list of all M2M clients
  3. Filter by status (Active, Revoked, All)
  4. Sort by creation date, name, or last used
  5. View usage statistics per client

Endpoint: GET /oauth/clients

Authentication: Requires Admin group membership

Request:

Terminal window
curl -X GET "https://{api-base-url}/oauth/clients?status=active" \
-H "Authorization: Bearer YOUR_ADMIN_ID_TOKEN"

Query Parameters:

ParameterDescriptionExample
statusFilter by statusactive, revoked

Response (200 OK):

{
"clients": [
{
"clientId": "abc123xyz456def789ghi012",
"clientName": "WooCommerce Integration",
"description": "Production WooCommerce catalog sync",
"scopes": ["products.read", "brands.read"],
"status": "active",
"createdAt": "2025-11-25T10:30:00Z",
"createdBy": { "userId": "a1b2c3d4-...", "userName": "Jane Smith" },
"lastUsedAt": "2025-11-25T14:22:31Z",
"usageCount": 1247
},
{
"clientId": "def456ghi789jkl012mno345",
"clientName": "Analytics Dashboard",
"description": "Read-only analytics access",
"scopes": ["products.read", "brands.read"],
"status": "active",
"createdAt": "2025-11-20T08:15:00Z",
"createdBy": { "userId": "e5f6g7h8-...", "userName": "John Doe" },
"lastUsedAt": "2025-11-25T09:45:12Z",
"usageCount": 8923
}
],
"count": 2
}

Revocation immediately prevents a client from obtaining new access tokens. Use this when:

  • An integration is decommissioned
  • Credentials are compromised
  • Access is no longer needed
  • Testing is complete
  1. Navigate to Settings → API Access
  2. Find the client to revoke
  3. Click “Revoke” button
  4. Confirm revocation in dialog
  5. Client status changes to “Revoked”

Endpoint: DELETE /oauth/clients/{clientId}

Authentication: Requires Admin group membership

Request:

Terminal window
curl -X DELETE https://{api-base-url}/oauth/clients/abc123xyz456def789ghi012 \
-H "Authorization: Bearer YOUR_ADMIN_ID_TOKEN"

Response (200 OK):

{
"message": "M2M client revoked successfully",
"clientId": "abc123xyz456def789ghi012",
"clientName": "WooCommerce Integration",
"revokedAt": "2025-11-25T15:45:00Z",
"revokedBy": {
"userId": "user-uuid-123",
"userName": "admin@example.com"
},
"note": "New tokens cannot be generated. Existing access tokens are rejected from the next API request (if the revocation check is temporarily unavailable, they are accepted until they expire)."
}
  1. t=0s: Admin revokes client via API/UI
  2. t=0s: Client status updated to revoked
  3. t=0s: Client cannot obtain new tokens (the authorizer does not cache decisions, so there is no propagation delay)
  4. t=0s: Existing access tokens are rejected from the next API request (if the revocation check is temporarily unavailable, they are accepted until they expire)

Total Time: New tokens blocked immediately; existing tokens rejected from the next API request

FeatureRevocationExpiration
ActionManual admin actionAutomatic at expiration date
SpeedImmediate (new tokens); next API request (existing tokens)Exact timestamp
Existing TokensRejected from the next API requestValid until expiration
ReversibleNo (must create new client)No (must create new client)
Use CaseCompromised credentials, decommissioned integrationTemporary access, testing, time-limited projects

Due to AWS Cognito limitations, client secrets cannot be rotated via API. Secrets are generated once and cannot be changed.

To rotate credentials:

  1. Create a new M2M client with the same scopes
  2. Update your integration to use the new credentials
  3. Test the new client thoroughly
  4. Revoke the old client once migration is complete

Ask your CRM administrator to rotate a client’s secret if needed — this is a manual, administrator-assisted process outside the API.

⚠️ Risk: Manual rotation can break existing integrations. Use the create-new-client approach instead.

Use descriptive, consistent names:

Good Examples:

  • WooCommerce_Production
  • Shopify_Staging
  • Analytics_Dashboard_v2
  • Mobile_App_iOS

Bad Examples:

  • Test123
  • Client1
  • MyApp

Principle of Least Privilege:

  • Grant only required scopes
  • Create separate clients for different integrations
  • The M2M API is read-only, so grant only the read scopes your integration uses

Example:

IntegrationScopes
WooCommerce (catalog sync)products.read, brands.read
Brand Catalog Widgetbrands.read
Reporting (products only)products.read
  1. Store secrets securely

    • Use environment variables (not hardcoded)
    • Use secret management systems (AWS Secrets Manager, Vault)
    • Never commit secrets to version control
  2. Monitor usage

    • Review usage counts regularly
    • Investigate unexpected spikes
    • Set up CloudWatch alarms for anomalies
  3. Audit regularly

    • Review client list monthly
    • Revoke unused clients
    • Check scope grants are still appropriate
  4. Document ownership

    • Maintain inventory of clients and their purposes
    • Record which team/person owns each integration
    • Include contact information for emergencies

Creation:

  • Document purpose and owner
  • Set expiration for temporary access
  • Grant minimum required scopes

Active Use:

  • Monitor usage metrics
  • Rotate secrets periodically (create new client)
  • Update descriptions as integrations evolve

Decommissioning:

  • Revoke client when integration is retired
  • Document revocation reason
  • Verify no systems still depend on it

Error: "Admin role required for this operation"

Solution: Ensure you’re authenticated with an admin Cognito ID token (not an M2M access token)

Error: "Client name must be at least 3 characters long"

Solution: Verify name meets requirements:

  • 3-100 characters
  • Alphanumeric, spaces, hyphens, underscores only

Error: "Invalid scope: crm-api/products.delete"

Solution: Use only valid scopes:

  • products.read, products.write
  • brands.read, brands.write

clients.* and quotes.* are not valid scopes — clients and quotes are not M2M resources, and the endpoint rejects those scope names.

Problem: Client secret was not saved during creation

Solution: There is no way to retrieve lost secrets. You must:

  1. Create a new M2M client
  2. Update your integration with new credentials
  3. Revoke the old client

Track these metrics per client:

  • Total API Calls: usageCount field
  • Last Used: lastUsedAt timestamp
  • Active/Inactive: Identify unused clients
  • Error Rates: Monitor 401/403 responses returned to your integration

All client management operations are logged:

  • Client creation (who, when, scopes)
  • Client revocation (who, when, reason)
  • Failed authorization attempts
  • Scope violations