# OAuth Callback HTTP 500 Error Fix

**Last Updated:** 2026-03-06

## Problem

OAuth registration was working correctly (user received success email and could log in), but at the end of the registration flow, users saw an HTTP 500 error page. The callback URL showed the error even though registration succeeded.

**Symptoms:**
- OAuth registration completes successfully
- User receives welcome email
- User can log in successfully
- But callback redirect shows HTTP 500 error
- Error occurs at: `https://www.ordio.com/partner/oauth/callback?state=...&code=...`

## Root Cause

The OAuth callback handler (`v2/pages/partner-oauth-callback.php`) lacked output buffering and safe redirect handling. Helper functions called after successful registration (`oauthCreatePartnerInHubSpot()`, `sendWelcomeEmail()`, `sendLoopUpdateToSlack()`, `updatePartnerLastLogin()`) could output content (error messages, warnings, whitespace) before the redirect, causing "headers already sent" error → HTTP 500.

**Specific issues:**
1. No output buffering at start of file
2. No `headers_sent()` check before redirects
3. Helper functions not wrapped in try-catch (could throw exceptions)
4. No buffer cleanup before redirects
5. No JavaScript fallback if headers already sent

## Solution Implemented

### 1. Output Buffering

Added output buffering at the start of the file (after includes, before any logic):

```php
// Start output buffering to prevent "headers already sent" errors
if (ob_get_level() === 0) {
    ob_start();
}
```

### 2. Safe Redirect Helper

Created `safeRedirect()` helper function similar to `produkt_updates_admin.php`:

- Checks `headers_sent()` before redirect
- Cleans output buffers before redirect
- Validates redirect URL
- JavaScript fallback if headers already sent
- Diagnostic logging for production debugging

### 3. Error Handling

Wrapped all helper calls in try-catch blocks:

- `oauthCreatePartnerInHubSpot()` - Non-blocking, errors logged but don't fail registration
- `sendWelcomeEmail()` - Non-blocking, errors logged but don't fail registration
- `sendLoopUpdateToSlack()` - Non-blocking, errors logged but don't fail registration
- `updatePartnerLastLogin()` - Non-blocking, errors logged but don't fail registration
- `session_regenerate_id()` - Critical, wrapped in try-catch with error redirect

### 4. Comprehensive Error Handling

Wrapped entire callback logic in try-catch:

- Catches `Exception` and `Throwable`
- Logs fatal errors with context
- Redirects to login with error message on fatal errors

### 5. Replaced All Redirects

Replaced all `header('Location: ...')` calls with `safeRedirect()`:

- `redirectToLogin()` - Now uses `safeRedirect()`
- `redirectToRegister()` - Now uses `safeRedirect()`
- Existing user redirect - Now uses `safeRedirect()`
- New user redirect - Now uses `safeRedirect()`

## Files Modified

- `v2/pages/partner-oauth-callback.php` - Complete refactor with safe redirects, error handling, and HubSpot creation fix

## Testing

After fix:
- ✅ OAuth registration completes without HTTP 500 errors
- ✅ Redirect works correctly
- ✅ Error logs show no "headers already sent" errors
- ✅ Registration completes successfully even if helper functions fail

## Prevention

This pattern should be used for any page that:
- Calls multiple helper functions before redirecting
- May have output from helper functions
- Needs reliable redirects in production

**Reference:** Similar pattern implemented in `v2/pages/produkt_updates_admin.php` with `safeRedirect()` helper.

## HubSpot Object Creation Fix

**Issue:** OAuth-registered partners were not getting HubSpot custom objects created.

**Root Cause:**
- `oauthCreatePartnerInHubSpot()` function duplicated code instead of using shared helper
- Function silently failed if `HUBSPOT_API_TOKEN` was not defined
- Result was never checked - function called but return value ignored
- No error logging when HubSpot creation failed

**Fix:**
- Removed duplicate `oauthCreatePartnerInHubSpot()` function
- Replaced with shared `createAffiliatePartnerInHubSpot()` helper from `hubspot-affiliate-api.php`
- Added proper error checking and logging
- Matches pattern used in regular email registration

**Backfill:**
- Use `v2/scripts/affiliate/backfill-oauth-hubspot-objects.php` to create missing HubSpot objects for existing OAuth-registered partners
- Supports `--dry-run` flag and `--partner-id=AP-XXX` for specific partners

## Related Documentation

- [SLACK_LOOP_UPDATES.md](SLACK_LOOP_UPDATES.md) - Slack integration overview
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - General troubleshooting guide
- [HUBSPOT_BACKFILL.md](HUBSPOT_BACKFILL.md) - Backfill script documentation
