# Testing & Validation Guide
This guide documents tested External Client App (ECA) and Connected App patterns based on systematic validation testing (December 2025).
## Test Matrix
| Component Type | Template / Source | Test Status |
|----------------|-------------------|-------------|
| Connected App (Basic) | `connected-app-basic.xml` | ✅ Verified |
| Connected App (Full OAuth) | `connected-app-oauth.xml` | ✅ Verified |
| Connected App (JWT Bearer) | `connected-app-jwt.xml` | ✅ Verified |
| Connected App (Canvas) | `connected-app-canvas.xml` | ⚠️ Location-dependent |
| External Client App | `external-client-app.xml` | ✅ Verified |
| ECA Global OAuth | `eca-global-oauth.xml` | ✅ Verified |
| ECA OAuth Settings | `eca-oauth-settings.xml` | ✅ Verified |
| ECA OAuth Security Settings | retrieve-first (`ExtlClntAppOauthSecuritySettings`) | ✅ CLI/registry-supported |
| ECA Configurable Policies | `eca-policies.xml` | ✅ Naming updated |
---
## Critical File Naming Conventions
### External Client App Files
| Metadata Type | Source Directory | File Suffix | Example |
|--------------|------------------|-------------|---------|
| ExternalClientApplication | `externalClientApps/` | `.eca-meta.xml` | `externalClientApps/MyApp.eca-meta.xml` |
| ExtlClntAppOauthSettings | `extlClntAppOauthSettings/` | `.ecaOauth-meta.xml` | `extlClntAppOauthSettings/MyApp.ecaOauth-meta.xml` |
| ExtlClntAppGlobalOauthSettings | `extlClntAppGlobalOauthSets/` | `.ecaGlblOauth-meta.xml` | `extlClntAppGlobalOauthSets/MyApp.ecaGlblOauth-meta.xml` |
| ExtlClntAppOauthSecuritySettings | `extlClntAppOauthSecuritySettings/` | `.ecaOauthSecurity-meta.xml` | `extlClntAppOauthSecuritySettings/MyApp.ecaOauthSecurity-meta.xml` |
| ExtlClntAppOauthConfigurablePolicies | `extlClntAppOauthPolicies/` | `.ecaOauthPlcy-meta.xml` | `extlClntAppOauthPolicies/MyApp.ecaOauthPlcy-meta.xml` |
| ExtlClntAppConfigurablePolicies | `extlClntAppPolicies/` | `.ecaPlcy-meta.xml` | `extlClntAppPolicies/MyApp.ecaPlcy-meta.xml` |
⚠️ **CRITICAL**:
- Use `.ecaGlblOauth` (abbreviated), NOT `.ecaGlobalOauth`
- Use `.ecaPlcy`, NOT `.ecaPolicy`
- `ExtlClntAppOauthSecuritySettings` is now source-supported; prefer retrieve-first until you have an org-validated sample file
### Connected App Files
| Metadata Type | File Suffix | Example |
|--------------|-------------|---------|
| ConnectedApp | `.connectedApp-meta.xml` | `MyApp.connectedApp-meta.xml` |
---
## Common Deployment Errors & Solutions
### Error: "Invalid or missing field" in ECA OAuth Settings
**Cause**: Using wrong schema with non-existent fields
**Wrong Schema (FAILS):**
```xml
true
true
Api
```
**Correct Schema:**
```xml
Api, RefreshToken
MyApp
```
### Error: "Missing required field" in ECA Global OAuth
**Cause**: Missing `externalClientApplication` or `label`
**Wrong (FAILS):**
```xml
https://example.com/callback
true
```
**Correct:**
```xml
https://example.com/callback
MyApp
true
false
true
false
false
false
```
### Error: "Organization is not configured to support location"
**Cause**: Canvas app using location that requires org feature enablement
**Problematic Locations:**
- `AppLauncher` - Requires feature enablement
- Some other locations may have similar requirements
**Solution**: Use universally available locations:
```xml
Visualforce
```
### Error: Certificate not found (JWT Bearer)
**Cause**: Referenced certificate doesn't exist in org
**Wrong:**
```xml
NonExistent_Cert
```
**Solution**: Create certificate first, then reference it:
```bash
# 1. Create certificate in org (Setup > Certificate and Key Management)
# 2. Reference in Connected App
My_JWT_Cert
```
---
## Field Reference
### ExtlClntAppOauthSettings (ECA OAuth)
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `commaSeparatedOauthScopes` | String | Yes | Comma-separated scopes (e.g., "Api, RefreshToken") |
| `externalClientApplication` | String | Yes | Reference to parent ECA API name |
| `label` | String | Yes | Display label |
**Available Scopes:**
- `Api` - REST/SOAP API access
- `RefreshToken` - Offline access
- `OpenID` - OpenID Connect
- `Profile` - User profile info
- `Email` - User email
- `Web` - Web browser access
- `ChatterApi` - Chatter REST API
### ExtlClntAppGlobalOauthSettings (ECA Global OAuth)
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `callbackUrl` | URL | Yes | OAuth redirect URI |
| `externalClientApplication` | String | Yes | Reference to parent ECA |
| `isConsumerSecretOptional` | Boolean | No | True for public clients with PKCE |
| `isIntrospectAllTokens` | Boolean | No | Enable token introspection |
| `isPkceRequired` | Boolean | No | Require PKCE (recommended for public clients) |
| `isSecretRequiredForRefreshToken` | Boolean | No | Require secret for refresh |
| `label` | String | Yes | Display label |
| `shouldRotateConsumerKey` | Boolean | No | Enable key rotation |
| `shouldRotateConsumerSecret` | Boolean | No | Enable secret rotation |
---
## Deployment Order
For External Client Apps, deploy in this order:
```bash
# 1. Deploy base ECA first
sf project deploy start --metadata ExternalClientApplication:MyApp --target-org [alias]
# 2. Deploy OAuth settings
sf project deploy start --metadata ExtlClntAppOauthSettings:MyApp --target-org [alias]
# 3. Deploy Global OAuth (if needed)
sf project deploy start --metadata ExtlClntAppGlobalOauthSettings:MyApp --target-org [alias]
# 4. Deploy companion security/policy metadata when you use it
sf project deploy start --metadata ExtlClntAppOauthSecuritySettings:MyApp --target-org [alias]
sf project deploy start --metadata ExtlClntAppOauthConfigurablePolicies:MyApp --target-org [alias]
sf project deploy start --metadata ExtlClntAppConfigurablePolicies:MyApp --target-org [alias]
# Or deploy the whole package directory when all ECA source directories live under it
sf project deploy start --source-dir force-app/main/default --target-org [alias]
```
---
## Post-Deployment Steps
### Client Credentials Flow (ECA)
Client Credentials flow still requires post-deployment admin validation. Even with broader metadata support, verify these items in Setup after deployment:
1. **Create Permission Set** with "Salesforce API Integration" permission
2. **Assign Permission Set** to the External Client App
3. **Confirm the run-as / execution-user behavior and any org-specific OAuth security settings**
### JWT Bearer Flow (Connected App)
1. **Upload Certificate** to org before deployment
2. **Pre-authorize Users** after deployment (Setup > Manage Connected Apps)
---
## Deployment Checklist
### External Client App
- [ ] `.eca-meta.xml` file exists under `externalClientApps/`
- [ ] `.ecaOauth-meta.xml` file exists under `extlClntAppOauthSettings/`
- [ ] `.ecaGlblOauth-meta.xml` uses abbreviated suffix under `extlClntAppGlobalOauthSets/`
- [ ] Optional companion files use the right suffixes: `.ecaOauthSecurity`, `.ecaOauthPlcy`, `.ecaPlcy`
- [ ] All companion files reference the same `externalClientApplication` name
- [ ] Required files include `label` where applicable
- [ ] `commaSeparatedOauthScopes` uses string format, not individual `` tags
- [ ] Callback URL is HTTPS (or custom scheme for mobile)
- [ ] PKCE enabled for public clients
### Connected App
- [ ] `.connectedApp-meta.xml` file exists
- [ ] `contactEmail` is valid
- [ ] Callback URL matches OAuth flow requirements
- [ ] Certificate exists in org (for JWT Bearer)
- [ ] Canvas locations are supported by org (if using Canvas)
---
## Tested Configurations
### Minimal ECA (API Integration)
```
Files:
├── externalClientApps/MyApp.eca-meta.xml
├── extlClntAppOauthSettings/MyApp.ecaOauth-meta.xml
└── extlClntAppGlobalOauthSets/MyApp.ecaGlblOauth-meta.xml
Scopes: Api, RefreshToken
PKCE: false (confidential client)
```
### Mobile App ECA (PKCE)
```
Files:
├── externalClientApps/MobileApp.eca-meta.xml
├── extlClntAppOauthSettings/MobileApp.ecaOauth-meta.xml
└── extlClntAppGlobalOauthSets/MobileApp.ecaGlblOauth-meta.xml
Scopes: Api, RefreshToken, OpenID
PKCE: true (public client)
Callback: com.example.app://oauth/callback
```
### Server-to-Server ECA
```
Files:
├── externalClientApps/ServiceApp.eca-meta.xml
├── extlClntAppOauthSettings/ServiceApp.ecaOauth-meta.xml
└── extlClntAppOauthSecuritySettings/ServiceApp.ecaOauthSecurity-meta.xml # retrieve-first when source controlling OAuth security settings
Scopes: Api
Note: Client Credentials still requires post-deployment Permission Set assignment and admin verification
```
---
*Last Updated: April 2026*
*Based on testing with SF CLI and API v66.0*