315 lines
9.0 KiB
Markdown
315 lines
9.0 KiB
Markdown
# 🔄 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
|
|
```typescript
|
|
// 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
|
|
```typescript
|
|
// 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
|
|
```typescript
|
|
// 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
|
|
```typescript
|
|
// 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):
|
|
```typescript
|
|
{
|
|
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:
|
|
|
|
1. **Receive the callback** from Salesforce
|
|
2. **Extract** query parameters: `user_uuid`, `service_name`, `code`
|
|
3. **Exchange** authorization code for tokens with Salesforce:
|
|
```http
|
|
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}
|
|
```
|
|
4. **Store** tokens (encrypted) in database
|
|
5. **Return** success/error HTML page:
|
|
- Success: Redirect to `?status=success`
|
|
- Error: Redirect to `?status=error&message=ERROR_MESSAGE`
|
|
|
|
#### Example Response (Success):
|
|
```html
|
|
<!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](src/modules/integrations/screens/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:
|
|
|
|
```bash
|
|
# .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](src/modules/integrations/screens/SALESFORCE_BACKEND_CALLBACK_FLOW.md).
|
|
|
|
---
|
|
|
|
## Testing the Updated Flow
|
|
|
|
### Test Checklist:
|
|
|
|
1. **Start Backend Server**
|
|
- Ensure backend is running
|
|
- Verify callback endpoint is accessible
|
|
- For local testing, use ngrok: `ngrok http 4000`
|
|
|
|
2. **Update Configuration**
|
|
- Update `BACKEND_BASE_URL` in `SalesforceAuth.tsx`
|
|
- Update Salesforce Connected App callback URL
|
|
- Restart mobile app
|
|
|
|
3. **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
|
|
|
|
4. **Verify Token Storage**
|
|
- Check database for stored tokens
|
|
- Verify tokens are encrypted
|
|
- Verify associated with correct user_id
|
|
|
|
5. **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
|
|
|
|
- [x] Update `SalesforceAuth.tsx` configuration
|
|
- [x] Update OAuth URL builder to include user_uuid
|
|
- [x] Add backend callback detection logic
|
|
- [x] Simplify navigation handler
|
|
- [ ] **Implement backend `/oauth/callback` endpoint**
|
|
- [ ] **Update Salesforce Connected App callback URL**
|
|
- [ ] **Configure backend environment variables**
|
|
- [ ] **Test end-to-end flow**
|
|
- [ ] **Verify token storage in database**
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Implement Backend Endpoint**: Follow the guide in [SALESFORCE_BACKEND_CALLBACK_FLOW.md](src/modules/integrations/screens/SALESFORCE_BACKEND_CALLBACK_FLOW.md)
|
|
|
|
2. **Update Salesforce Config**: Change callback URL in Connected App settings
|
|
|
|
3. **Test Thoroughly**: Test authentication flow with both success and error scenarios
|
|
|
|
4. **Deploy**: Deploy backend changes and update mobile app configuration
|
|
|
|
---
|
|
|
|
**Updated**: October 2025
|
|
**Status**: ✅ Mobile App Updated - Backend Implementation Required
|
|
**Version**: 2.0.0
|
|
|