Advanced Extensions
#Credentials
#Overview
Credentials allow your UI extensions to make authenticated calls to external APIs and services. When you configure credentials for your extension, they are securely stored in the PIM and automatically included as headers in your API requests.
This system provides several key benefits:
- Security: Credentials are encrypted before storage and never exposed to the browser
- Server-side Execution: All authenticated API calls are made server-side
- Ease of Use: Simply reference a credential code in your extension - no manual header management needed
- Multiple Authentication Methods: Support for Bearer tokens, Basic Auth, and custom headers
#Available Credential Methods
| Method | Header Format | Use Case |
|---|---|---|
| Bearer Token | Authorization: Bearer {token_value} |
OAuth 2.0, API tokens |
| Basic Authentication | Authorization: Basic {base64(username:password)} |
Username/password APIs |
| Custom Header | {custom_header_key}: {custom_header_value} |
Custom authentication schemes |
#Configuring Credentials
#Via the PIM UI
When creating or editing a UI extension in the PIM interface, you can add credentials in the credentials section:
- Select Authentication Method: Choose from Bearer Token, Basic Auth, or Custom Header
- Assign a Credential Code: Enter a unique code to identify this credential (e.g.,
erp_api_token) - Enter Credential Values:
- Bearer Token: Enter the token value
- Basic Auth: Enter username and password
- Custom Header: Enter the header key and value
- Save: Credentials are encrypted and stored securely
#Via the API
When deploying extensions via the REST API, you can include credentials in your request:
curl --location '{YOUR_PIM_HOST}/api/rest/v1/ui-extensions' \
--header 'Authorization: Bearer {YOUR_API_TOKEN}' \
--form 'name="my_extension"' \
--form 'type="sdk_script"' \
--form 'credentials[0][code]="api_credentials"' \
--form 'credentials[0][type]="Bearer Token"' \
--form 'credentials[0][value]="your_token_value"'
#Using Credentials in Your Extension
#External API Calls with Credentials
The SDK provides the PIM.api.external.call() method for making authenticated requests to external APIs. Use the credentials_code parameter to reference stored credentials:
// Make an authenticated GET request
const response = await PIM.api.external.call({
method: 'GET',
url: 'https://api.example.com/data',
credentials_code: 'api_credentials' // References the stored credential
});
const data = await response.json();
console.log('Data from external API:', data);
#Credential Codes
Each credential is identified by a unique code that you define when creating the credential. This code is used in your extension to reference which credential should be used for the API call.
Example with Bearer Token:
// Configured credential code: 'erp_bearer_token'
// Type: Bearer Token
// Value: 'abc123xyz789'
const erpData = await PIM.api.external.call({
method: 'GET',
url: 'https://erp.example.com/api/products',
credentials_code: 'erp_bearer_token'
});
The PIM will automatically add the header: Authorization: Bearer abc123xyz789
Example with Basic Auth:
// Configured credential code: 'warehouse_auth'
// Type: Basic Authentication
// Username: 'api_user'
// Password: 'secret_password'
const inventory = await PIM.api.external.call({
method: 'GET',
url: 'https://warehouse.example.com/api/inventory',
credentials_code: 'warehouse_auth'
});
The PIM will automatically add the header: Authorization: Basic {base64(api_user:secret_password)}
Example with Custom Header:
// Configured credential code: 'custom_api_key'
// Type: Custom Header
// Header Key: 'X-API-Key'
// Header Value: 'my-secret-key-12345'
const externalData = await PIM.api.external.call({
method: 'POST',
url: 'https://service.example.com/api/data',
credentials_code: 'custom_api_key',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: 'products' })
});
The PIM will automatically add the header: X-API-Key: my-secret-key-12345
#Multiple Credentials
You can configure multiple credentials for a single extension and use different credentials for different API calls:
// Use ERP credentials for inventory data
const inventory = await PIM.api.external.call({
method: 'GET',
url: 'https://erp.example.com/inventory',
credentials_code: 'erp_credentials'
});
// Use CRM credentials for customer data
const customers = await PIM.api.external.call({
method: 'GET',
url: 'https://crm.example.com/customers',
credentials_code: 'crm_credentials'
});
#Security Best Practices
#Never Hardcode Credentials
❌ Don't do this:
// BAD: Credentials exposed in browser
const response = await PIM.api.external.call({
method: 'GET',
url: 'https://api.example.com/data',
headers: {
'Authorization': 'Bearer my-secret-token-12345' // NEVER DO THIS!
}
});
✅ Do this instead:
// GOOD: Use stored credentials
const response = await PIM.api.external.call({
method: 'GET',
url: 'https://api.example.com/data',
credentials_code: 'api_token' // Secure, server-side
});
#Why This Matters
Your extension code runs in the user's browser. Any credentials hardcoded in your JavaScript file can be:
- Viewed in browser developer tools
- Extracted from network requests
- Stolen by malicious users
By using the credentials_code parameter:
- Credentials are stored encrypted in the PIM database
- API calls are made server-side by the PIM
- Credentials never reach the browser or client-side code
- Your sensitive data remains protected
#Additional Security Tips
- Rotate Credentials Regularly: Update stored credentials periodically
- Use Least Privilege: Grant only the minimum permissions needed for external APIs
- Monitor Usage: Track which extensions are accessing external services
- Validate Responses: Always validate data received from external APIs
- Handle Errors Gracefully: Don't expose sensitive information in error messages
#Complete Example
Here's a complete example showing credential setup and usage:
// Extension configuration has these credentials:
// - Code: 'product_api_token'
// - Type: Bearer Token
// - Value: (stored securely in PIM)
async function syncProductData(productUuid) {
try {
// Get product data from PIM
const product = await PIM.api.product_uuid_v1.get({
uuid: productUuid
});
// Send to external service using credentials
const response = await PIM.api.external.call({
method: 'POST',
url: 'https://external-service.com/api/products',
credentials_code: 'product_api_token',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
sku: product.identifier,
name: product.values.name,
price: product.values.price
})
});
if (response.ok) {
const result = await response.json();
console.log('Product synced successfully:', result);
return result;
} else {
throw new Error(`API error: ${response.status}`);
}
} catch (error) {
console.error('Sync failed:', error.message);
// Handle error appropriately
}
}
#Troubleshooting
#Credential Not Found
If you see an error about credentials not being found:
- Verify the
credentials_codematches exactly what was configured - Check that the credential is saved in the extension configuration
- Ensure the extension has been redeployed after adding credentials
#Unauthorized Errors
If external API calls return 401 or 403 errors:
- Verify the credential values are correct
- Check if the external API token has expired
- Ensure the external API endpoint allows requests from your PIM server IP
#Domain Allowlisting
Remember that external API domains must be allowlisted in your extension configuration for security purposes.
