多客户端应用下Azure AD/Microsoft Graph令牌选型及离线访问问题
Hey there, let's tackle this problem head-on. The issue you're facing is that implicit flow doesn't return refresh tokens—something you absolutely need for offline, backend-driven access to Hotmail/Outlook accounts. Here's a step-by-step guide to get this working across your Laravel/Lumen, Cordova, and Angular platforms:
Implicit flow is designed for frontend-only SPAs and only returns short-lived access tokens—no refresh tokens, which makes it useless for offline backend processing. To fix this, you need to switch to the Authorization Code Flow (with PKCE for mobile/SPA apps) and explicitly request the offline_access scope.
First, update your Microsoft app configuration:
- Navigate to your app in the Microsoft portal
- Go to the "Authentication" section
- Enable the Authorization Code Flow (for web apps, ensure client credentials are allowed; for SPAs/mobile, check "Allow public client flows" and enable PKCE support)
- Verify your redirect URIs are correctly set for each platform (web app callback, Cordova deep link, Angular SPA route)
offline_access Scope Every authorization request from your apps must include the offline_access scope, plus any Outlook-specific permissions your monitoring needs (e.g., Mail.Read, Mail.ReadWrite). A sample scope parameter would look like:
scope=openid profile offline_access Mail.Read
Since offline processing happens on your backend, all token handling should be routed through it to keep credentials secure. Here's how to set this up for each platform:
3.1 Laravel/Lumen Web Apps
Use tools like Laravel Socialite (with a Microsoft provider) or the official Microsoft Graph SDK to simplify implementation:
- Configure Socialite to request the
offline_accessscope in your auth setup - When the user completes authorization, your backend will receive an authorization code. Exchange this code for an access token and refresh token via Microsoft's token endpoint
- Store the refresh token (encrypted!) alongside the user's record in your database
- For offline tasks, check if the access token is expired. If it is, use the refresh token to fetch a new access token:
// Example using Laravel's HTTP client $tokenResponse = Http::post('https://login.microsoftonline.com/common/oauth2/v2.0/token', [ 'client_id' => env('MICROSOFT_CLIENT_ID'), 'client_secret' => env('MICROSOFT_CLIENT_SECRET'), 'refresh_token' => $user->encrypted_microsoft_refresh_token, 'grant_type' => 'refresh_token', 'scope' => 'offline_access Mail.Read', ]); $newTokens = $tokenResponse->json(); // Update the user's tokens (refresh tokens may roll over, so always save the new one) $user->update([ 'microsoft_access_token' => $newTokens['access_token'], 'encrypted_microsoft_refresh_token' => encrypt($newTokens['refresh_token']), ]);
3.2 Cordova Mobile Apps
Mobile apps are public clients (can't safely store client secrets), so use PKCE with the Authorization Code Flow:
- Use a Cordova OAuth plugin (or implement PKCE manually) to initiate the authorization request with
offline_accessscope - After the user authorizes, you'll get an authorization code. Send this code to your backend instead of exchanging it directly in the app
- Your backend handles the token exchange and stores the refresh token. The app only needs a short-lived access token for frontend interactions; all offline processing happens server-side
3.3 Angular SPA
Like mobile apps, SPAs can't store client secrets securely—use PKCE with Authorization Code Flow:
- Use an Angular OAuth library (e.g.,
angular-oauth2-oidc) configured to enable PKCE and request theoffline_accessscope - Once the user authorizes, pass the authorization code to your backend. The backend exchanges it for tokens and stores the refresh token
- The SPA requests short-lived access tokens from your backend when needed, and all offline tasks are handled exclusively by your server
- Encrypt Refresh Tokens: Always encrypt refresh tokens before storing them in your database—never store plaintext credentials
- Handle Token Expiry: Refresh tokens expire after 90 days (or if the user revokes access). Build logic to prompt users to re-authorize if refresh fails
- Respect Rate Limits: Microsoft Graph has API rate limits—throttle your offline tasks to avoid being blocked
- Allow Token Revocation: Give users a way to revoke access to their accounts, which should trigger your backend to delete the stored refresh token and call Microsoft's revocation endpoint
Note: Microsoft may roll over refresh tokens after use, so always update the stored refresh token with the new one returned in the refresh response.
内容的提问来源于stack exchange,提问作者techwestcoastsfosea

