# SSO Redirect - Test Results

## Environment
- **Org-recruiter**: http://localhost:8096
- **New recruiter**: http://localhost:8095
- **Database**: recruiter_prod_local (local MySQL on port 3308)
- **Date**: 2026-03-13

---

## Test Scenarios

### D. SSO Token Flow (New Recruiter Side)

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| D1 | Valid token consumed | PASS | Token consumed, session created, dashboard shows user name. Tested with users 2, 7, 83044. |
| D2 | Expired token | PASS | Redirects to `login.php?error=token_expired` |
| D3 | Already used token | PASS | Redirects to `login.php?error=token_used` |
| D4 | Invalid token format | PASS | Redirects to `login.php?error=invalid_token` (handles empty, missing, non-hex) |
| D5 | Non-existent token | PASS | Redirects to `login.php?error=token_not_found` |
| D6 | Token for inactive user | PASS | Redirects to `login.php?error=user_not_found` (user 22, status=0) |
| D7 | Token for user with no company | PASS | Redirects to `login.php?error=no_company` (user 1) |

### B. Dashboard Banner (SSO eligibility check)

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| B1 | Verified user eligibility | PASS | Returns `eligible: true` with email and company IDs (user 2) |
| B2 | Unverified company user | PASS | Returns `eligible: false, reason: not_verified` (user 58180, Dummy Inc) |
| B3 | No-email verified user | PASS | Returns `eligible: false, reason: no_email` with message (user 77009) |
| B4 | Non-recruiter user | PASS | Returns `eligible: false, reason: not_recruiter` (user 1, no role_id=3) |

### A. Login/OTP Flow

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| A1 | Verified recruiter OTP → SSO redirect | PASS (code review) | `otpVerifyProcess()` calls `get_sso_redirect_url()`, sets `sso_redirect=true` in response. JS handles redirect. |
| A2 | Unverified recruiter OTP → old dashboard | PASS (code review) | `get_sso_redirect_url()` returns null for unverified, falls through to dashboard redirect. |
| A3 | Verified recruiter with no email | PASS (code review) | Returns error array with `no_email` reason, sets `sso_error` message, redirects to old dashboard. |
| A4 | Verified recruiter with no ats_password | PASS | `ensure_ats_password()` auto-sets bcrypt hash of `k@abil2020`. Tested with user 83044 (had no ats_password, was auto-set, SSO login succeeded). Audit table logged the action. |

### C. Constructor Redirects

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| C1 | Verified recruiter visits /recruiter/login | PASS | Redirects to SSO URL (307 → sso-login.php?token=...) |
| C2 | Verified recruiter visits /recruiter/register | PASS | Redirects to SSO URL (307 → sso-login.php?token=...) |
| C3 | Unverified company user visits /recruiter/login | PASS | Redirects to /recruiter/dashboard (no SSO) |
| C4 | No-email verified user visits /recruiter/login | PASS | Redirects to /recruiter/dashboard (no SSO, shows error on dashboard) |
| C5 | Not-profile-verified user visits /recruiter/login | PASS | Redirects to /recruiter/register/addCompany (onboarding flow) |

### F. Superadmin Company Verification

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| F1 | Auto-set ats_password on approval | PASS | SQL correctly updates users without ats_password in approved company. Tested with company 70. |
| F2 | Ensure user_roles on approval | PASS | INSERT ON DUPLICATE KEY UPDATE correctly ensures role_id=3 entries. |
| F3 | Email notification on approval | PASS (code review) | Brevo API integration code present. Sends to all company users with email. Cannot test without sending real emails. |

### G. Feature Flag

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| G1 | Feature flag disabled (ENABLE_NEW_RECRUITER_REDIRECT=false) | PASS | Verified user redirects to old dashboard, NOT SSO. Dashboard banner hidden. |

### H. Error Display

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| H1 | SSO errors on new recruiter login | PASS | All 8 error codes show appropriate alert-danger messages on login page |
| H2 | SSO error on old dashboard | PASS | No-email verified user sees alert-warning with "add your email address" message |

### E. End-to-End Flow

| # | Scenario | Status | Finding |
|---|----------|--------|---------|
| E1 | Org-recruiter generates token → new recruiter consumes → dashboard | PASS | Full flow tested with users 2, 7, 83044. Token generated, consumed, session created, dashboard rendered. |
| E2 | Token marked used after consumption | PASS | `used_at` correctly set, preventing reuse. |
| E3 | Auto-activate user without ats_password via SSO | PASS | User 83044 had no ats_password, got auto-set, SSO login succeeded. |

---

## Fix Log

| # | Issue Found | Fix Applied | Date |
|---|------------|-------------|------|
| 1 | **Timezone mismatch**: PHP IST (`Asia/Kolkata`) vs MySQL UTC caused `strtotime()` to interpret stored UTC datetime as IST, making valid tokens appear expired. | Changed `generate_sso_token()` to use `UTC_TIMESTAMP()` instead of PHP `date()`. Changed `sso-login.php` to compare expiry via SQL `UTC_TIMESTAMP()` instead of PHP `time()`. | 2026-03-13 |
| 2 | **API_BASE not set in Docker**: `$_SERVER['HTTP_HOST']` is `localhost:8096` (not `localhost`), so the condition failed and `API_BASE` defaulted to `/` (empty `DOMAIN_NAME` env). | Added `elseif(strpos($_SERVER['HTTP_HOST'], 'localhost:') === 0)` case in `constants.php` to set `API_BASE = 'http://localhost/'` for Docker. | 2026-03-13 |

---

## Data Validation (Database State)

| Metric | Count |
|--------|-------|
| Verified company users with role_id=3 | 230 |
| Verified company users WITHOUT role_id=3 | 0 |
| Verified users with ats_password | 177 |
| Verified users without ats_password | 53 (auto-set on first SSO) |
| Verified users with no email | 1+ (get error message, stay on old dashboard) |

---

## Files Modified

| File | Changes |
|------|---------|
| `org-recruiter/application/helpers/ats_redirect_helper.php` | Fixed `generate_sso_token()` to use `UTC_TIMESTAMP()` |
| `org-recruiter/application/config/constants.php` | Fixed `API_BASE` for Docker, added feature flag |
| `recruiter/public/sso-login.php` | Fixed expiry check to use `UTC_TIMESTAMP()` SQL comparison |
