I’ve troubleshot this exact scenario multiple times across different ThingWorx deployments. The issue is more complex than it initially appears and involves understanding ThingWorx’s multi-layered permission model:
Understanding Role-Based API Permissions:
ThingWorx has separate permission layers that all must align for API access:
- Thing-level permissions (PropertyRead, ServiceInvoke)
- Role-based visibility permissions
- Runtime permissions for service execution
- Composer access permissions (affects API authentication)
Role Inheritance Issues:
When you change user roles, inherited permissions don’t always propagate correctly for API access:
- Web mashups use cached permission evaluations
- API calls perform real-time permission checks
- This creates the situation where mashups work but API calls fail
Diagnostic Steps:
First, verify the actual permission state:
GET /Thingworx/Resources/CurrentSessionInfo
// Returns current user's roles and permissions
// Compare with expected permissions
Composer Permission Settings:
Navigate to the data-stream thing in Composer:
- Open the thing (e.g., SensorDataStream)
- Go to Permissions tab
- Verify the new role is listed with these permissions:
- PropertyRead: Checked (for reading temperature property)
- ServiceInvoke: Checked (for API service calls)
- Visibility: Checked (for thing discovery)
Role Inheritance Configuration:
Check role inheritance chain:
- Go to Organizations & Users > Roles
- Find the new role assigned to users
- Verify inheritance from parent roles
- Look for permission conflicts or overrides
- Ensure ServiceInvoke is explicitly granted, not just inherited
Critical: Explicit vs Inherited Permissions:
API permission evaluation prioritizes explicit permissions over inherited ones:
- If parent role has ServiceInvoke but child role doesn’t explicitly grant it
- API calls may fail even though inheritance suggests permission exists
- Solution: Explicitly grant ServiceInvoke to the new role at the thing level
Implementation Fix:
// Pseudocode - Grant explicit API permissions:
1. Open data-stream thing (SensorDataStream) in Composer
2. Navigate to Permissions tab
3. Click Add Permission button
4. Select the new role (e.g., DataAnalyst)
5. Check ServiceInvoke and PropertyRead
6. Apply changes and save thing
// Reference: Security Guide Section 6.3
Session and Cache Clearing:
After permission changes:
- Have all affected users logout completely
- Clear browser cache and cookies
- If using API keys, regenerate them
- Clear ThingWorx session cache (restart Session Manager subsystem)
- Test API access with fresh authentication
Verification Testing:
Test API permissions systematically:
// Test property read
GET /Thingworx/Things/SensorDataStream/Properties/temperature
// Test service invoke
POST /Thingworx/Things/SensorDataStream/Services/GetDataStream
Both should return 200 OK if permissions are correct.
Common Permission Gotchas:
- Runtime Permissions: Even with thing permissions, users need Runtime > ServiceInvoke permission
- Organization Scope: If thing is in a specific organization, role must have access to that org
- Visibility Restrictions: Thing must be visible to the role (check Visibility permission)
- Instance-Level Permissions: Permissions set on thing templates don’t automatically apply to instances
Best Practice Implementation:
For role-based API access:
- Create explicit permission grants (don’t rely solely on inheritance)
- Grant permissions at thing level, not just role level
- Test API access immediately after role changes
- Document permission requirements for each role
- Implement permission validation in CI/CD pipeline
Audit and Monitoring:
Enable detailed permission logging:
- Set log level to DEBUG for Security subsystem
- Monitor ApplicationLog for permission denial messages
- Look for specific error codes indicating permission type (403.1 vs 403.2)
- Use audit logs to track permission changes
After implementing these changes, your API access should be restored. The key issue is that role inheritance doesn’t reliably grant ServiceInvoke permissions for API calls - you need explicit permission grants at the thing level for the new role.