OAuth2接入Microsoft:REST获取Office 365日历事件遇令牌验证失败求助
Hey there! Let’s work through this together—you’ve got your Azure app set up with OAuth2, but hitting that annoying "Access token validation failure" when trying to pull Office 365 Calendar events via the REST API. And since you only found Laravel examples, I’ll hook you up with a straightforward, WordPress-friendly code snippet that works universally. Let’s start with fixing that token error first, then dive into the code.
This error usually stems from one of these common issues—let’s rule them out first:
- Incorrect permissions: Make sure your Azure app has the right Graph API permissions (like
Calendars.ReadorCalendars.ReadBasic.All). If you’re using delegated permissions, ensure the user has consented to them; for application permissions, confirm your admin has granted them. - Wrong audience (
audclaim): Your token’saudvalue must behttps://graph.microsoft.com—any other value will fail validation. You can decode the token with a local JWT tool to check this. - Expired token: Check the
expclaim in your token to make sure it hasn’t expired. If it has, you’ll need to fetch a new one. - Invalid signature: Ensure you’re using the correct tenant ID, client ID, and client secret when fetching the token—mismatched values will produce an invalid signature.
Below is a self-contained snippet you can drop into your WordPress theme’s functions.php file or a custom plugin. It handles token retrieval, event fetching, and adds a shortcode to display events on any page/post.
<?php /** * Fetch a valid Microsoft Graph access token */ function get_ms_graph_access_token() { // Replace these with your Azure app credentials $tenant_id = 'YOUR_TENANT_ID'; $client_id = 'YOUR_CLIENT_ID'; $client_secret = 'YOUR_CLIENT_SECRET'; $scope = 'https://graph.microsoft.com/Calendars.Read'; $token_endpoint = "https://login.microsoftonline.com/{$tenant_id}/oauth2/v2.0/token"; // Set up request to Azure token endpoint $request_args = array( 'body' => array( 'grant_type' => 'client_credentials', // Use 'authorization_code' for user-specific events 'client_id' => $client_id, 'client_secret' => $client_secret, 'scope' => $scope ), 'headers' => array( 'Content-Type' => 'application/x-www-form-urlencoded' ), 'timeout' => 15, 'sslverify' => true ); $response = wp_remote_post($token_endpoint, $request_args); if (is_wp_error($response)) { error_log('MS Graph Token Error: ' . $response->get_error_message()); return false; } $response_body = json_decode(wp_remote_retrieve_body($response), true); // Store token in transient to avoid repeated requests (optimization) if (isset($response_body['access_token'])) { set_transient('ms_graph_token', $response_body['access_token'], $response_body['expires_in'] - 60); return $response_body['access_token']; } error_log('MS Graph Token Retrieval Failed: ' . print_r($response_body, true)); return false; } /** * Fetch Office 365 Calendar events from Microsoft Graph * @param int $limit Number of events to fetch * @return array|false Array of events or false on failure */ function get_o365_calendar_events($limit = 10) { // Get token (use transient if available) $access_token = get_transient('ms_graph_token') ?: get_ms_graph_access_token(); if (!$access_token) { return false; } // Use '/me/events' for delegated permissions (current user), or '/users/{USER_ID}/events' for app permissions $graph_endpoint = "https://graph.microsoft.com/v1.0/me/events?\$top={$limit}&\$select=subject,start,end,location"; $request_args = array( 'headers' => array( 'Authorization' => "Bearer {$access_token}", 'Content-Type' => 'application/json' ), 'timeout' => 15, 'sslverify' => true ); $response = wp_remote_get($graph_endpoint, $request_args); if (is_wp_error($response)) { error_log('MS Graph Events Error: ' . $response->get_error_message()); return false; } $response_body = json_decode(wp_remote_retrieve_body($response), true); return isset($response_body['value']) ? $response_body['value'] : false; } /** * Shortcode to display calendar events on WordPress pages/posts */ add_shortcode('display_o365_calendar', function() { $events = get_o365_calendar_events(5); if (!$events) { return '<p>Sorry, we couldn’t load your calendar events right now. Please check your Azure app configuration.</p>'; } $output = '<ul class="o365-calendar-events">'; foreach ($events as $event) { $subject = esc_html($event['subject']); $start_time = date('F j, Y g:i a', strtotime($event['start']['dateTime'])); $end_time = date('F j, Y g:i a', strtotime($event['end']['dateTime'])); $location = isset($event['location']['displayName']) ? esc_html($event['location']['displayName']) : 'No location specified'; $output .= "<li> <h3>{$subject}</h3> <p><strong>Time:</strong> {$start_time} – {$end_time}</p> <p><strong>Location:</strong> {$location}</p> </li>"; } $output .= '</ul>'; return $output; }); ?>
- Permission Type Adjustment:
- Use
client_credentials(application permissions) if you’re fetching events from a shared/company calendar (you’ll need to replace/me/eventswith/users/{USER_EMAIL_OR_ID}/eventsin the graph endpoint). - Use
authorization_code(delegated permissions) if you want to show the logged-in WordPress user’s personal calendar—this requires adding an OAuth login flow for Microsoft (let me know if you need help with that!).
- Use
- Token Optimization: The code uses WordPress transients to cache the token, so you don’t hit Azure’s API limits with repeated requests.
- Error Logging: Errors are logged to WordPress’s error log (check
wp-content/debug.logif you’ve enabled debugging) to help you troubleshoot issues.
- Replace the placeholder values (tenant ID, client ID, client secret) with your Azure app’s details.
- Add the shortcode
[display_o365_calendar]to any WordPress page or post. - Preview the page—you should see a list of your calendar events if everything is set up correctly.
If you still get the token validation error, decode your token and double-check the aud, scp (or roles), and iss claims to ensure they match Microsoft Graph’s requirements.
内容的提问来源于stack exchange,提问作者rask

