We built a custom monitoring application using the Oracle IoT app enablement framework. Users keep getting logged out after exactly 60 minutes, and they have to re-authenticate completely. I’ve traced it to OAuth2 refresh token expiry. Our app flow:
// Initial auth
const authResponse = await oracleIoT.authenticate(credentials);
const accessToken = authResponse.access_token;
const refreshToken = authResponse.refresh_token;
// Later refresh attempt (fails after 60 min)
const newToken = await oracleIoT.refreshToken(refreshToken);
The refresh call returns 400 ‘invalid_grant’ after the 60-minute mark. I’ve checked the OAuth2 refresh token settings in the app configuration, and the token lifetime is set to 3600 seconds. But shouldn’t refresh tokens last longer than access tokens? This is breaking our automation workflows that need to run for hours. How do we extend the refresh token lifetime or implement proper session management?
The 60-minute limit you’re hitting is likely the refresh token absolute expiration, not the access token expiration. In IoT Platform, refresh tokens have both an idle timeout and an absolute timeout. Check your OAuth2 client configuration under Application Settings > Security. You need to increase the ‘Refresh Token Absolute Lifetime’ setting, which defaults to 3600 seconds.
Token rotation is the right approach, but you also need to handle the automation workflow impact. For long-running automated processes, consider using service accounts with client credentials flow instead of OAuth2 user tokens. Service accounts can use API keys that don’t expire, which is more suitable for automation. User-based OAuth2 is designed for interactive sessions, not for hours-long background jobs.
That makes sense for pure automation, but our app has both interactive user sessions and background automation triggered by users. We need both patterns to work. Can we use a hybrid approach where user sessions use OAuth2 with rotation, and background jobs spawn service account sessions?
Absolutely, and that’s actually the recommended architecture. Here’s the comprehensive solution:
OAuth2 Refresh Token Settings (for user sessions):
Navigate to Applications > [Your App] > OAuth2 Configuration:
-
Access Token Lifetime: 900 seconds (15 minutes)
- Short-lived access tokens minimize exposure window
- Forces regular refresh, keeping sessions active
-
Refresh Token Settings:
- Refresh Token Absolute Lifetime: 7200 seconds (2 hours)
- Refresh Token Idle Timeout: 1800 seconds (30 minutes)
- Enable ‘Rotate Refresh Tokens on Use’: YES (critical for security)
-
Token Rotation Implementation:
class IoTSessionManager {
constructor() {
this.accessToken = null;
this.refreshToken = null;
this.tokenExpiry = null;
}
async refreshSession() {
const response = await oracleIoT.refreshToken(this.refreshToken);
// Store NEW refresh token (rotation)
this.refreshToken = response.refresh_token;
this.accessToken = response.access_token;
this.tokenExpiry = Date.now() + (response.expires_in * 1000);
}
async ensureValidToken() {
if (Date.now() >= this.tokenExpiry - 60000) {
await this.refreshSession();
}
return this.accessToken;
}
}
Session Management Best Practices:
- Proactively refresh tokens 1 minute before expiry
- Implement exponential backoff for refresh failures
- Clear tokens on logout to prevent reuse
- Store refresh tokens securely (never in localStorage)
Automation Workflow Impact (hybrid solution):
For background jobs initiated by users:
-
Short-duration automation (< 2 hours):
- Use the user’s OAuth2 session with token refresh
- Monitor token expiry and refresh proactively
- Handle refresh failures gracefully (pause job, notify user)
-
Long-duration automation (> 2 hours):
- Switch to service account after user initiates
- Create service account specifically for automation: Administration > Service Accounts > Create
- Use client credentials flow:
const automationToken = await oracleIoT.authenticate({
grant_type: 'client_credentials',
client_id: 'automation-service-account',
client_secret: process.env.SERVICE_ACCOUNT_SECRET
});
3. **Hybrid Implementation:**
- User authenticates with OAuth2 for interactive UI
- When user triggers automation workflow:
a. Validate user has permission to run automation
b. Record user identity for audit trail
c. Switch to service account credentials for execution
d. Job runs with service account (no expiry issues)
e. Results are associated with original user for reporting
**Security Considerations:**
- Enable 'Require PKCE' for OAuth2 flows (prevents authorization code interception)
- Set 'Allowed Redirect URIs' to exact URLs (no wildcards)
- Implement proper CORS policies for your app domain
- Monitor OAuth2 audit logs for suspicious refresh patterns
**Testing Token Rotation:**
```bash
# Verify rotation is working
curl -X POST https://iot.oraclecloud.com/oauth2/token \
-d "grant_type=refresh_token" \
-d "refresh_token=<old-token>" \
-d "client_id=<your-client-id>"
# Try using old refresh token again (should fail)
curl -X POST https://iot.oraclecloud.com/oauth2/token \
-d "grant_type=refresh_token" \
-d "refresh_token=<old-token>" \
-d "client_id=<your-client-id>"
# Expected: 400 invalid_grant
This hybrid approach gives you secure user sessions with automatic refresh for interactive use, while long-running automation uses service accounts that don’t have the same token lifecycle constraints. The key is separating user identity (for authorization and audit) from execution credentials (for reliability).