From 291fb761c79fcd1901a8ca64f5336b4f42bf7bf7 Mon Sep 17 00:00:00 2001 From: Niek Rabelink Date: Thu, 10 Sep 2026 14:42:19 +0200 Subject: [PATCH] feat(microsoft-integration): enhance email permissions and consent flow for Outlook integration --- admin.php | 2 +- auth/callback_microsoft.php | 11 +++++-- auth/oauth_microsoft.php | 11 ++++++- includes/integrations/microsoft.php | 32 +++++++++++------- mail.php | 50 ++++++++++++++++++++++++----- planner.php | 9 +++++- profile.php | 8 ++--- 7 files changed, 95 insertions(+), 28 deletions(-) diff --git a/admin.php b/admin.php index 1dcb0b1..75196ce 100644 --- a/admin.php +++ b/admin.php @@ -516,7 +516,7 @@ require_once __DIR__ . '/includes/header.php';
3
- API Permissions: Ga naar API permissions → Add a permission → Microsoft Graph → Delegated permissions → Vink aan: User.Read en Calendars.ReadWrite. + API Permissions: Ga naar API permissions → Add a permission → Microsoft Graph → Delegated permissions → Vink aan: User.Read, Calendars.ReadWrite, Mail.ReadWrite en Mail.Send.
diff --git a/auth/callback_microsoft.php b/auth/callback_microsoft.php index d397439..4be4e25 100644 --- a/auth/callback_microsoft.php +++ b/auth/callback_microsoft.php @@ -138,7 +138,14 @@ $saveStmt = $db->prepare(" "); $saveStmt->execute([$user['id'], $accessToken, $refreshToken, json_encode($newSettings)]); -// 8. Succesvol terugkeren naar de Persoonlijke Profiel Hub -header('Location: /profile.php?success=' . urlencode("Microsoft Outlook succesvol gekoppeld als {$accountEmail}!")); +// 8. Succesvol terugkeren naar de gewenste pagina of het Persoonlijk Profiel +$returnTo = $_SESSION['ms_oauth_return_to'] ?? '/profile.php'; +unset($_SESSION['ms_oauth_return_to']); + +$redirectUrl = ($returnTo === '/mail.php') + ? '/mail.php?success=' . urlencode("Microsoft Outlook 365 e-mail & agenda succesvol gekoppeld als {$accountEmail}!") + : '/profile.php?success=' . urlencode("Microsoft Outlook succesvol gekoppeld als {$accountEmail}!"); + +header('Location: ' . $redirectUrl); exit; diff --git a/auth/oauth_microsoft.php b/auth/oauth_microsoft.php index 2257126..c7e785a 100644 --- a/auth/oauth_microsoft.php +++ b/auth/oauth_microsoft.php @@ -43,8 +43,17 @@ $state = generate_oauth_state((int)$user['id']); $_SESSION['ms_oauth_state'] = $state; $_SESSION['ms_oauth_user_id'] = (int)$user['id']; +// Onthoud eventuele gewenste terugkeerpagina (bijv. /mail.php) +if (!empty($_GET['return_to'])) { + $_SESSION['ms_oauth_return_to'] = trim($_GET['return_to']); +} else { + unset($_SESSION['ms_oauth_return_to']); +} + +$forceConsent = !empty($_GET['reconsent']) || !empty($_GET['force']); + // Stuur gebruiker door naar Microsoft login -$authUrl = microsoft_get_auth_url($clientId, $redirectUri, $tenantId, $state); +$authUrl = microsoft_get_auth_url($clientId, $redirectUri, $tenantId, $state, $forceConsent); header("Location: {$authUrl}"); exit; diff --git a/includes/integrations/microsoft.php b/includes/integrations/microsoft.php index 7c7bbbf..16f3a01 100644 --- a/includes/integrations/microsoft.php +++ b/includes/integrations/microsoft.php @@ -10,7 +10,7 @@ require_once __DIR__ . '/../../config/database.php'; const MS_OAUTH_AUTHORIZE_URL = 'https://login.microsoftonline.com/%s/oauth2/v2.0/authorize'; const MS_OAUTH_TOKEN_URL = 'https://login.microsoftonline.com/%s/oauth2/v2.0/token'; const MS_GRAPH_BASE_URL = 'https://graph.microsoft.com/v1.0'; -const MS_DEFAULT_SCOPES = 'offline_access User.Read Calendars.ReadWrite Mail.ReadWrite Mail.Send'; +const MS_DEFAULT_SCOPES = 'offline_access User.Read Calendars.ReadWrite Mail.ReadWrite Mail.Send OnlineMeetings.ReadWrite'; /** * Haalt de centrale Microsoft App Registratie configuratie op (Client ID, Secret, Tenant ID) @@ -125,7 +125,7 @@ function microsoft_get_app_config(): array { /** * Genereert de Microsoft OAuth2 login URL */ -function microsoft_get_auth_url(string $clientId, string $redirectUri, string $tenantId = '', string $state = ''): string { +function microsoft_get_auth_url(string $clientId, string $redirectUri, string $tenantId = '', string $state = '', bool $forceConsent = false): string { $tenant = (!empty($tenantId) && $tenantId !== 'common') ? trim($tenantId) : 'planningsagenda.nl'; $baseUrl = sprintf(MS_OAUTH_AUTHORIZE_URL, urlencode($tenant)); @@ -136,7 +136,7 @@ function microsoft_get_auth_url(string $clientId, string $redirectUri, string $t 'response_mode' => 'query', 'scope' => MS_DEFAULT_SCOPES, 'state' => $state, - 'prompt' => 'select_account', + 'prompt' => $forceConsent ? 'consent' : 'select_account', ]; return $baseUrl . '?' . http_build_query($params); @@ -1038,16 +1038,26 @@ function microsoft_fetch_inbox_messages(int $userId, int $limit = 25, bool $unre ]); if ($res['status'] !== 200 || !isset($res['json']['value'])) { - error_log("Microsoft fetch inbox error: HTTP {$res['status']} - " . ($res['error'] ?? json_encode($res['json']))); - // Val terug op demo data indien API fout optreedt + $graphError = $res['json']['error']['message'] ?? ($res['error'] ?? 'HTTP ' . $res['status']); + $graphCode = $res['json']['error']['code'] ?? ''; + error_log("Microsoft fetch inbox error: HTTP {$res['status']} [{$graphCode}] - {$graphError}"); + $demo = microsoft_get_mail_demo_data(); + $needsReconsent = ($res['status'] === 403 || stripos($graphError, 'access') !== false || stripos($graphError, 'privilege') !== false || stripos($graphError, 'denied') !== false || stripos($graphError, 'consent') !== false); + return [ - 'success' => true, - 'is_demo' => true, - 'messages' => array_slice($demo, 0, $limit), - 'unread_count' => count(array_filter($demo, function($m) { return empty($m['is_read']); })), - 'total_count' => count($demo), - 'warning' => 'Kon live e-mails niet ophalen van Microsoft Graph. Demomodus actief.', + 'success' => true, + 'is_demo' => true, + 'messages' => array_slice($demo, 0, $limit), + 'unread_count' => count(array_filter($demo, function($m) { return empty($m['is_read']); })), + 'total_count' => count($demo), + 'warning' => $needsReconsent + ? 'Je Microsoft koppeling mist machtiging voor e-mail (Mail.ReadWrite). Autoriseer opnieuw om je inbox live in te laden.' + : 'Kon live e-mails niet ophalen van Microsoft Graph (' . $graphError . '). Demomodus actief.', + 'needs_reconsent' => $needsReconsent, + 'graph_error' => $graphError, + 'graph_code' => $graphCode, + 'http_status' => $res['status'], ]; } diff --git a/mail.php b/mail.php index ddaa330..b4772e9 100644 --- a/mail.php +++ b/mail.php @@ -16,18 +16,33 @@ $inboxData = microsoft_fetch_inbox_messages($userId, 30); $messages = $inboxData['messages'] ?? []; $isDemo = !empty($inboxData['is_demo']); $unreadCount = (int)($inboxData['unread_count'] ?? 0); +$warning = $inboxData['warning'] ?? ''; +$needsReconsent = !empty($inboxData['needs_reconsent']); // Controleer status $stmtInt = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK' AND is_enabled = 1"); $stmtInt->execute([$userId]); $outlookInt = $stmtInt->fetch(); -$isLiveOutlook = !empty($outlookInt['access_token']) && empty($outlookInt['is_demo_mode']); +$isOutlookConfigured = !empty($outlookInt['access_token']) && empty($outlookInt['is_demo_mode']); +$isLiveMail = $isOutlookConfigured && !$isDemo; $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP); ?>
+ +
+ + +
+ +
+ + +
+ +
@@ -35,8 +50,10 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q
Microsoft Outlook 365 • Inbox - + LIVE VERBONDEN + + E-MAIL MACHTIGING VEREIST DEMO INBOX @@ -56,10 +73,10 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q Vernieuwen - - + + - Live Outlook Koppelen + @@ -70,13 +87,30 @@ $jsonMessages = json_encode($messages, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_Q
- + + +
- Je bekijkt momenteel een interactieve demonstratieset. Koppel je zakelijke Microsoft 365 account via Profiel om al je live zakelijke e-mails in te laden. + Je bekijkt momenteel een interactieve demonstratieset. Koppel je zakelijke Microsoft 365 account om al je live zakelijke e-mails in te laden.
- Nu koppelen → + Nu koppelen →
diff --git a/planner.php b/planner.php index 9abe6b0..631f386 100644 --- a/planner.php +++ b/planner.php @@ -234,10 +234,12 @@ try { // 5b. Haal recente e-mails op voor de Outlook E-mail Widget $recentEmails = []; $unreadEmailCount = 0; +$mailNeedsReconsent = false; try { $mailData = microsoft_fetch_inbox_messages($userId, 5); $recentEmails = $mailData['messages'] ?? []; $unreadEmailCount = (int)($mailData['unread_count'] ?? 0); + $mailNeedsReconsent = !empty($mailData['needs_reconsent']); } catch (Throwable $e) { error_log("Fout bij ophalen recente e-mails in planner: " . $e->getMessage()); } @@ -934,7 +936,12 @@ for ($h = $startHour; $h <= $endHour; $h++) {

Outlook E-mail

- 0): ?> + + + + Machtiging vereist → + + 0): ?> ongelezen diff --git a/profile.php b/profile.php index db03d06..64bced7 100644 --- a/profile.php +++ b/profile.php @@ -651,7 +651,7 @@ require_once __DIR__ . '/includes/header.php';
-

Mijn Microsoft 365 Agenda

+

Mijn Microsoft 365 (Agenda & E-mail)

@@ -663,14 +663,14 @@ require_once __DIR__ . '/includes/header.php';
-

Synchroniseer uw agenda-afspraken automatisch met uw dagplanning

+

Synchroniseer uw agenda-afspraken en zakelijke Outlook e-mails met Fociz

- - Opnieuw Verbinden + + Machtigingen Bijwerken
-- 2.52.0