# Microsoft (Employee Portal) Login – Frontend Integration

## Problem

On the login page, the **"Employee Portal"** button refreshed the page instead of redirecting to Microsoft SSO because the frontend was not performing a **full-page redirect** to the backend URL that starts the Microsoft OAuth flow.

## Backend Flow

1. **Start Microsoft login:** Backend exposes a **web** route `GET /auth/redirect` that redirects the user to Microsoft's login page.
2. **Callback:** After the user signs in with Microsoft, they are sent to backend `GET /auth/callback`, which logs them in and redirects to the frontend (e.g. `/employee-login-loading`).

## Fix for the Frontend (Employee Portal button)

The "Employee Portal" button must **navigate the browser** to the backend URL that triggers the Microsoft redirect. It must **not** only call an API that returns JSON (like `check-social-login`) without then redirecting.

### Option A – Use the new API (recommended)

1. **Request:**  
   `GET /api/v1/web/auth/microsoft-redirect-url`  
   (no auth, same base URL as your API)

2. **Response:**  
   `{ "redirect_url": "https://<backend-domain>/auth/redirect" }`

3. **Frontend behaviour:**  
   When the user clicks "Employee Portal":
   - Call `GET /api/v1/web/auth/microsoft-redirect-url`.
   - Then set **full-page location** to the returned URL, e.g.  
     `window.location.href = response.data.redirect_url`  
     (or `response.redirect_url` depending on your API response shape).

Example (conceptual):

```javascript
// When "Employee Portal" button is clicked
async function onEmployeePortalClick() {
  const baseUrl = process.env.VUE_APP_API_BASE_URL || 'https://roms.roqay.dev/api/v1/web';
  const res = await fetch(`${baseUrl}/auth/microsoft-redirect-url`);
  const data = await res.json();
  const url = data.redirect_url || data.data?.redirect_url;
  if (url) {
    window.location.href = url;  // full-page redirect – do not use router.push or fetch only
  }
}
```

Important: use **`window.location.href = url`** (or equivalent full-page navigation). Do **not** use `router.push(url)` if that keeps the user on the same SPA; do **not** only fetch the URL and do nothing with it.

### Option B – Direct URL (if backend base URL is fixed)

If the frontend knows the backend base URL (e.g. from env):

- Backend base: `https://roms.roqay.dev`
- Employee Portal link: **`https://roms.roqay.dev/auth/redirect`**

Set the button to open that URL in the same window (full-page navigation), e.g.:

- `<a href="https://roms.roqay.dev/auth/redirect">Employee Portal</a>`, or  
- `window.location.href = 'https://roms.roqay.dev/auth/redirect'`

Again: the navigation must be a **full page load** to the backend, not a client-side route or API call that leaves the user on the login page.

## Why the page was “refreshing” before

- The frontend likely called an endpoint (e.g. `check-social-login`) that **returns JSON** and does **not** redirect.
- Or it used a link/button that triggered a same-origin navigation (e.g. SPA route) instead of going to the backend `/auth/redirect` URL.
- So the user stayed on (or “refreshed”) the login page instead of being sent to Microsoft.

## Summary

| What | URL / action |
|------|------------------|
| Get redirect URL (API) | `GET /api/v1/web/auth/microsoft-redirect-url` → use `response.redirect_url` |
| Start Microsoft login (browser) | Full-page navigate to `redirect_url` (e.g. `https://app.roms.roqay.dev/auth/redirect`) |
| Do **not** | Only fetch JSON without redirecting, or use SPA router for this step |

---

## Redirect successfully after Microsoft login – checklist

For the user to land on the app as logged in after Microsoft SSO, ensure the following.

### 1. Backend `.env`

- **FRONTEND_URL** = base URL of the app (where the user should land after login):
  ```env
  FRONTEND_URL=https://app.roms.roqay.dev
  ```
- **MICROSOFT_REDIRECT_URI** = exact callback URL (must match Azure). This should be the URL that serves your Laravel app (where `/auth/callback` is handled):
  ```env
  MICROSOFT_REDIRECT_URI=https://app.roms.roqay.dev/auth/callback
  ```
- **SESSION_DOMAIN** = shared cookie domain so the session works for both app and API if they use different subdomains:
  ```env
  SESSION_DOMAIN=.roqay.dev
  ```
- **SESSION_SECURE_COOKIE=true** (required when using HTTPS).

### 2. Azure Portal (App registration → Authentication)

- Add **Redirect URI**: `https://app.roms.roqay.dev/auth/callback` (must match `MICROSOFT_REDIRECT_URI` exactly).

### 3. Where `/auth/redirect` and `/auth/callback` are served (fix “no redirect” after callback)

- The callback URL is where **Microsoft** sends the user after login (with `?code=...`). **That request must be handled by Laravel** so the controller can exchange the code, log the user in, and redirect to the frontend.
- **If no redirect happens** when you land on `.../auth/callback?code=...` (page stays on callback or shows the Vue app), the callback is **not** reaching Laravel (e.g. app.roms.roqay.dev serves only the frontend SPA).

**Fix: use the backend domain for the callback**

- Set the callback to the **domain where Laravel runs** (e.g. sys):
  ```env
  MICROSOFT_REDIRECT_URI=https://sys.roms.roqay.dev/auth/callback
  ```
- In **Azure** → App registration → Authentication, add: `https://sys.roms.roqay.dev/auth/callback`.
- Flow: user → app.roms.roqay.dev/auth/redirect → Microsoft → **sys.roms.roqay.dev/auth/callback** (Laravel) → redirect to app.roms.roqay.dev/employee-login-loading.
- Keep **SESSION_DOMAIN=.roqay.dev** so the session cookie set on sys is sent when the app (on app) calls the API.

**Alternative:** If you want the callback to stay on app.roms.roqay.dev, that host must run Laravel (or proxy `/auth/callback` and `/auth/redirect` to the backend).

### 4. After callback – redirect to app

- The callback controller redirects to `FRONTEND_URL + '/employee-login-loading'` on success (e.g. `https://app.roms.roqay.dev/employee-login-loading`).
- It calls `session()->save()` before redirect so the session cookie is persisted.

### 5. Frontend – `/employee-login-loading` page

- On load, call `GET /api/v1/web/check-social-login` **with credentials** so the session cookie is sent:
  ```javascript
  fetch(`${API_BASE}/check-social-login`, { credentials: 'include' })
  ```
- If the response is **200**, the user is logged in; use the returned user data and redirect to the dashboard (or home).
- If the response is **401**, show a message or redirect to login.

### 6. If the API is on a different subdomain (e.g. sys.roms.roqay.dev)

- All API requests from the frontend (app.roms.roqay.dev) must use **`credentials: 'include'`** (or equivalent) so the session cookie (domain `.roqay.dev`) is sent.
- Keep **SESSION_DOMAIN=.roqay.dev** so the cookie is valid for both app and sys.

### 7. Fix: “Wrong Credentials” after Microsoft login (check-social-login returns 401)

This usually means the request to **check-social-login** does not see the session (auth()->user() is null).

**Cause:** The session was created when the user hit the **callback** (e.g. on sys). If the frontend then calls the API on a **different server** (e.g. app), that server has its own session store (e.g. file). So it does not have that session → “Wrong Credentials”.

**Do this:**

1. **Call the same backend that handled the callback**  
   Set the frontend API base URL to the **callback domain** (e.g. `https://sys.roms.roqay.dev`). So after redirect to app.roms.roqay.dev/employee-login-loading, the call to `check-social-login` goes to **sys.roms.roqay.dev** and the session cookie is sent to the same server that has the session.

2. **Send credentials**  
   Use `credentials: 'include'` (or your HTTP client’s equivalent) for `check-social-login` and for all API requests that need the session.

3. **If app and sys are different servers and you must call the API on both**  
   Use a **shared session store** so both servers see the same session:
   - In **.env**: `SESSION_DRIVER=database` (and run `php artisan session:table` + migrate), or `SESSION_DRIVER=redis` with a shared Redis.
   - Then the session created on sys is readable when the next request hits app (or the other way around), as long as they use the same store.
