如何刷新Outlook access_token?解决创建联系人invalid_token报错问题
Hey Jordan, let's work through these issues together—they're super common when dealing with Microsoft Graph and OAuth 2.0, so we'll get this sorted out.
Why You're Not Getting a Refresh Token
The offline_access scope is required to get a refresh token, but there are a few easy-to-miss details here:
- You must include
offline_accessin the initial authorization request (the one that gets you the authorization code), not just when exchanging the code for an access token. Microsoft only issues refresh tokens if the user explicitly grants offline access during the consent step. - Double-check your OAuth flow: If you're using the Implicit Flow (for public clients like single-page apps), it won't return a refresh token. You need to use the Authorization Code Flow (with or without PKCE, depending on your app type) to get a refresh token.
- Verify tenant and app permissions: In your Azure AD app registration, go to "API Permissions" and make sure
offline_accessis listed and marked as "Granted" (either by the user or an admin, depending on your app's consent settings). Some tenant admins restrict offline access, so this is worth checking.
Why Refreshing the Code Gives the Same Access Token
This is almost always due to a cached authorization session:
- When you request a new authorization code without forcing re-consent, the browser might reuse the existing session, giving you the same (or expired) code. Add the
prompt=consentparameter to your authorization request to force the user to re-authorize, which will generate a fresh code. - Also, authorization codes are one-time use—if you're reusing a code that's already been exchanged, you should get an error, but if you're seeing the same access token, it's likely the code itself isn't new.
Step-by-Step Fix for invalid_token & Missing Refresh Token
Let's walk through the exact steps to resolve this:
Generate a fresh authorization code with correct scopes
Construct your authorization URL with these parameters (replace placeholders with your app details):GET https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/authorize? client_id={your-client-id} &response_type=code &redirect_uri={your-redirect-uri} &response_mode=query &scope=Contacts.ReadWrite offline_access &prompt=consentThe
prompt=consentensures the user re-grants permissions, andContacts.ReadWriteis required to create Outlook contacts.Exchange the new code for tokens
Send a POST request to the token endpoint with these form-data parameters:POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token Content-Type: application/x-www-form-urlencoded client_id={your-client-id} &scope=Contacts.ReadWrite offline_access &code={fresh-authorization-code} &redirect_uri={your-redirect-uri} &grant_type=authorization_code &client_secret={your-client-secret} # Omit this if using PKCE for public clientsNow check the response—you should see a
refresh_tokenfield alongside theaccess_token.Validate your access token
Decode the access token (use a tool like jwt.io, but never share sensitive token data publicly) to confirm:- The
scpfield includesContacts.ReadWriteandoffline_access - The
exptimestamp is in the future (not expired) - The
aud(audience) ishttps://graph.microsoft.com
- The
Use the refresh token to get a new access token
When your access token expires, use this request to refresh it:POST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token Content-Type: application/x-www-form-urlencoded client_id={your-client-id} &scope=Contacts.ReadWrite offline_access &refresh_token={your-refresh-token} &grant_type=refresh_token &client_secret={your-client-secret}Check your API request for invalid_token
Ensure you're passing the access token correctly in the request header when calling the Outlook contacts API:POST https://graph.microsoft.com/v1.0/me/contacts Authorization: Bearer {valid-access-token} Content-Type: application/json { "givenName": "John", "surname": "Doe", "emailAddresses": [ { "address": "john.doe@example.com", "name": "John Doe" } ] }
If you still run into issues, double-check that your app registration's redirect URI matches exactly what's in your requests—even a small typo here can cause token validation failures.
内容的提问来源于stack exchange,提问作者Jordan

