We’re hitting OAuth2 token rejection errors when posting billing data from edge devices to Oracle IoT Cloud Platform via REST API. The authentication works fine for device telemetry endpoints, but billing data posts consistently fail with 401 Unauthorized.
Our current implementation:
POST /iot/api/v2/billing/events
Authorization: Bearer {token}
Content-Type: application/json
Error response indicates “insufficient claims” but doesn’t specify which claims are missing. We’re using the same OAuth2 token that works for other API calls. Is there a specific claim requirement for billing endpoints? Also wondering if multi-tenant header configuration plays a role here since we’re managing multiple client accounts. Any guidance on the required permission scopes for billing data sync would be appreciated.
I’ve seen this exact issue. Billing endpoints require additional OAuth2 claims beyond standard device API access. Check if your token includes the ‘billing:write’ scope. The multi-tenant scenario adds another layer - you need to include the X-Tenant-ID header in your request even if the token is tenant-specific. The billing API validates both the scope claim and the tenant header match.
Thanks both. I checked our OAuth client config and we don’t have the billing scope registered. When I try to add it through the console, should I use ‘billing:write’ or the full URN format ‘urn:oracle:iot:billing:write’? Also, for the X-Tenant-ID header - is this the organization ID from the IoT console or something different?
Use the full URN format when configuring the OAuth client. For the tenant header, it’s the Tenant ID from IoT Cloud Platform > Settings > Organization Details. Make sure you’re also sending X-Application-ID header with your registered application ID. Without both headers, the API can’t properly validate multi-tenant permissions even with correct token claims.
Let me provide a complete solution addressing all the OAuth2 token requirements, multi-tenant configuration, and permission scopes for billing API access.
OAuth2 Token Claim Requirements:
Your token must include these specific claims:
- scope: ‘urn:oracle:iot:billing:write’ (full URN format required)
- aud: Must include ‘https://iot.oraclecloud.com/billing’ in the audience array
- tenant_id: Your organization’s tenant identifier
- exp: Token expiration (note: billing tokens have 15-minute lifetime vs 60-minute for standard APIs)
Request token with proper scope:
POST /oauth2/v1/token
grant_type=client_credentials
scope=urn:oracle:iot:billing:write
client_id={your_client_id}
client_secret={your_client_secret}
Multi-Tenant API Header Configuration:
Billing endpoints require these headers:
POST /iot/api/v2/billing/events
Authorization: Bearer {token_with_billing_scope}
X-Tenant-ID: {org_tenant_id}
X-Application-ID: {registered_app_id}
Content-Type: application/json
The X-Tenant-ID must match the tenant_id claim in your token. Get this from IoT Console > Settings > Organization Details. X-Application-ID is your OAuth client ID registered in Applications > OAuth Clients.
REST API Permission Scopes:
Configure your OAuth client in IoT Cloud Platform console:
- Navigate to Applications > OAuth Clients > Your Application
- Add API Permissions: Select ‘Billing Services’ category
- Enable these specific scopes:
- urn:oracle:iot:billing:write (for POST operations)
- urn:oracle:iot:billing:read (if you need to query billing data)
- Save and regenerate client credentials
Critical Implementation Notes:
- Billing API validates both token claims AND request headers - both must align
- Token refresh is essential: Implement refresh logic at 12-minute intervals (before 15-min expiration)
- Multi-tenant validation: The platform verifies tenant_id claim matches X-Tenant-ID header AND your client is authorized for that tenant
- Rate limiting: Billing endpoints have stricter limits (100 req/min vs 500 for device APIs)
Verification Steps:
- Decode your JWT at jwt.io - verify all required claims are present
- Test with curl including all headers to isolate authentication from application code
- Check audit logs in IoT Console > Monitoring > API Access for detailed rejection reasons
- Ensure your OAuth client has ‘Billing API Access’ checkbox enabled in the console
The “insufficient claims” error specifically means either the scope claim is missing/wrong or the aud claim doesn’t include the billing service endpoint. Fix both in your token request, add the required headers, and your billing sync should work.
Adding to the previous comment - the permission scopes for billing are indeed stricter. You’ll need to request a token with explicit ‘urn:oracle:iot:billing:write’ scope during the OAuth2 flow. Standard device scopes won’t work. Also verify your client application is registered with billing API permissions in the IoT Cloud console under Applications > OAuth Clients.
One more thing to watch - token expiration for billing APIs is typically shorter (15 minutes vs 1 hour for device APIs). If you’re batching billing events, implement token refresh logic. I’ve seen scenarios where the first few posts succeed but later ones fail mid-batch because the token expired. Check the exp claim in your JWT to verify timing.
Quick tip on debugging - decode your JWT token at jwt.io to inspect the actual claims. You should see something like this in the payload for billing access to work properly. The aud claim must include the billing service endpoint, not just the base IoT platform URL. This catches a lot of people.