9.0 KiB
🔄 Salesforce OAuth - Backend Callback Flow Update
What Changed?
The Salesforce OAuth implementation has been updated to use a backend callback flow instead of a mobile deep-link scheme. This means the backend server handles the OAuth callback and token exchange directly.
Previous Flow vs New Flow
❌ Previous Flow (Deep Link)
Salesforce → Mobile App (deep link) → Send code to backend → Backend exchanges token
- Redirect URI:
centralizedreportingsystem://oauth/salesforce/callback - Problem: Custom scheme requires complex deep linking configuration
- Risk: Authorization code exposed to mobile app
✅ New Flow (Backend Callback)
Salesforce → Backend Server → Exchange token → Success page → Mobile app detects success
- Redirect URI:
https://YOUR_BACKEND_URL/api/v1/users/oauth/callback?user_uuid=USER_ID&service_name=salesforce - Benefits:
- Backend handles token exchange securely
- No need for deep linking configuration
- Authorization code never exposed to mobile app
- Standard OAuth 2.0 web flow
Code Changes
SalesforceAuth.tsx
1. Updated Configuration
// OLD
const SALESFORCE_CONFIG = {
CLIENT_ID: 'YOUR_CLIENT_ID',
REDIRECT_URI: 'centralizedreportingsystem://oauth/salesforce/callback',
AUTH_BASE_URL: 'https://login.salesforce.com',
};
// NEW
const SALESFORCE_CONFIG = {
CLIENT_ID: 'YOUR_CLIENT_ID',
BACKEND_BASE_URL: 'https://d5285bf63993.ngrok-free.app',
CALLBACK_PATH: '/api/v1/users/oauth/callback',
AUTH_BASE_URL: 'https://login.salesforce.com',
};
2. Updated OAuth URL Builder
// OLD
const buildSalesforceAuthUrl = (): string => {
const redirectUri = 'centralizedreportingsystem://oauth/salesforce/callback';
// ...
};
// NEW
const buildSalesforceAuthUrl = (userUuid: string): string => {
// Build redirect URI with query parameters for backend
const redirectUri = `${BACKEND_BASE_URL}${CALLBACK_PATH}?user_uuid=${userUuid}&service_name=salesforce`;
// ...
};
3. New Detection Functions
// Check if URL is the backend callback
const isBackendCallbackUri = (url: string): boolean => {
return url.includes('/api/v1/users/oauth/callback');
};
// Check for success
const isCallbackSuccess = (url: string): boolean => {
const status = getQueryParamFromUrl(url, 'status');
return status === 'success';
};
// Check for error
const isCallbackError = (url: string): boolean => {
const status = getQueryParamFromUrl(url, 'status');
return status === 'error' || status === 'failure';
};
4. Simplified Navigation Handler
// OLD - Mobile app handled token exchange
handleNavigationStateChange = (navState) => {
if (isRedirectUri(url) && authCode) {
handleAuthorizationCode(authCode); // Send code to backend
}
};
// NEW - Backend handles token exchange
handleNavigationStateChange = (navState) => {
if (isBackendCallbackUri(url)) {
if (isCallbackSuccess(url)) {
handleBackendSuccess(); // Just close modal
}
if (isCallbackError(url)) {
handleBackendError(url); // Show error
}
}
};
Backend Implementation Required
Endpoint: GET /api/v1/users/oauth/callback
Your backend must implement this endpoint to handle the OAuth callback from Salesforce.
Query Parameters (Received from Salesforce):
{
user_uuid: string; // User ID (passed in redirect_uri)
service_name: string; // 'salesforce' (passed in redirect_uri)
code: string; // Authorization code from Salesforce
}
Backend Responsibilities:
- Receive the callback from Salesforce
- Extract query parameters:
user_uuid,service_name,code - Exchange authorization code for tokens with Salesforce:
POST https://login.salesforce.com/services/oauth2/token grant_type=authorization_code code={CODE} client_id={CLIENT_ID} client_secret={CLIENT_SECRET} redirect_uri={CALLBACK_URL_WITH_PARAMS} - Store tokens (encrypted) in database
- Return success/error HTML page:
- Success: Redirect to
?status=success - Error: Redirect to
?status=error&message=ERROR_MESSAGE
- Success: Redirect to
Example Response (Success):
<!DOCTYPE html>
<html>
<head><title>Success</title></head>
<body>
<h1>✓ Authentication Successful!</h1>
<p>Your Salesforce account has been connected.</p>
<script>
// Mobile app will detect this URL
window.location.search = '?status=success';
</script>
</body>
</html>
See SALESFORCE_BACKEND_CALLBACK_FLOW.md for complete backend implementation guide.
Configuration Steps
1. Update Salesforce Connected App
In your Salesforce Connected App settings:
Old Callback URL:
centralizedreportingsystem://oauth/salesforce/callback
New Callback URL:
https://YOUR_BACKEND_URL/api/v1/users/oauth/callback
Note: Don't include query parameters in the Salesforce Connected App config. The app adds them dynamically.
2. Update Mobile App (Already Done ✅)
The SalesforceAuth.tsx component has been updated with:
- ✅ New backend callback URL configuration
- ✅ Detection logic for backend callback
- ✅ Success/error handling
- ✅ User UUID passed to backend
3. Configure Backend
Update your environment variables:
# .env
SALESFORCE_CLIENT_ID=3MVG9GBhY6wQjl2sueQtv2NXMm3EuWtEvOQoeKRAzYcgs2...
SALESFORCE_CLIENT_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
BACKEND_URL=https://d5285bf63993.ngrok-free.app
ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
4. Implement Backend Endpoint
Create the /api/v1/users/oauth/callback endpoint following the guide in SALESFORCE_BACKEND_CALLBACK_FLOW.md.
Testing the Updated Flow
Test Checklist:
-
Start Backend Server
- Ensure backend is running
- Verify callback endpoint is accessible
- For local testing, use ngrok:
ngrok http 4000
-
Update Configuration
- Update
BACKEND_BASE_URLinSalesforceAuth.tsx - Update Salesforce Connected App callback URL
- Restart mobile app
- Update
-
Test Authentication
- Open app → CRM & Sales → Salesforce
- Complete Salesforce login
- Expected: Redirect to backend URL
- Backend logs should show: "Received callback", "Token exchange successful", "Tokens stored"
- Mobile app should show: Success message, then close modal
-
Verify Token Storage
- Check database for stored tokens
- Verify tokens are encrypted
- Verify associated with correct user_id
-
Test Re-authentication
- Tap "Re-auth" button
- Complete flow again
- Verify tokens are updated in database
Debugging
Check Logs
Mobile App (React Native)
[SalesforceAuth] Built OAuth URL: https://login.salesforce.com/...
[SalesforceAuth] Redirect URI: https://YOUR_BACKEND/callback?user_uuid=...
[SalesforceAuth] Backend callback detected
[SalesforceAuth] Backend callback indicates success
Backend Server
[OAuth Callback] Received: { user_uuid: '...', service_name: 'salesforce', hasCode: true }
[OAuth Callback] Token exchange successful
[OAuth Callback] Tokens stored successfully
Common Issues
| Issue | Solution |
|---|---|
| Backend not reachable | Use ngrok for local testing: ngrok http 4000 |
| Callback URL mismatch | Update Salesforce Connected App with exact backend URL |
| Token exchange fails | Verify CLIENT_SECRET is correct in backend |
| Mobile app doesn't detect success | Ensure backend returns HTML with ?status=success |
Benefits of Backend Callback Flow
✅ More Secure: Authorization code never exposed to mobile app
✅ Simpler Configuration: No deep linking setup needed
✅ Standard OAuth: Follows standard web OAuth 2.0 flow
✅ Backend Control: Full control over token exchange and storage
✅ Better Error Handling: Backend can provide detailed error messages
✅ Token Refresh: Backend can implement automatic token refresh
Migration Checklist
- Update
SalesforceAuth.tsxconfiguration - Update OAuth URL builder to include user_uuid
- Add backend callback detection logic
- Simplify navigation handler
- Implement backend
/oauth/callbackendpoint - Update Salesforce Connected App callback URL
- Configure backend environment variables
- Test end-to-end flow
- Verify token storage in database
Next Steps
-
Implement Backend Endpoint: Follow the guide in SALESFORCE_BACKEND_CALLBACK_FLOW.md
-
Update Salesforce Config: Change callback URL in Connected App settings
-
Test Thoroughly: Test authentication flow with both success and error scenarios
-
Deploy: Deploy backend changes and update mobile app configuration
Updated: October 2025
Status: ✅ Mobile App Updated - Backend Implementation Required
Version: 2.0.0