SMTP XOAUTH2 token and correct SMTP username on limited-input printer

QA1 45 Reputation points
2026-06-30T06:10:10.14+00:00

We are developing a limited-input printer. The printer does not have a web browser, so we use Microsoft OAuth 2.0 Device Code Flow.

Our targets are:

  1. Obtain an access token that can be used to send email through SMTP AUTH XOAUTH2.
  2. Obtain the correct user name that should be used in the user= field of the SMTP AUTH XOAUTH2 SASL string.
  3. Require the end user to complete consent only one time in a web browser.

The SMTP AUTH XOAUTH2 SASL string format is:

base64("user=" + userName + "^Aauth=Bearer " + accessToken + "^A^A")

The main problem is how to reliably obtain the correct userName value.

We already tested following 4 methods, but all methods failed to achieve the above three targets at the same time.

Method 1:

Method 1 - Step 1:

HTTP
POST /common/oauth2/v2.0/devicecode HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/8.13.0
Accept: */*
Content-Length: 127
Content-Type: application/x-www-form-urlencoded

client_id=3caf90da-c45a-4a78-9fd1-f7aa22fca3b6&scope=https://graph.microsoft.com/User.Read https://outlook.office.com/SMTP.Send


HTTP/1.1 200 OK
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
x-ms-request-id: dc87aafd-b992-48ca-80db-91b062770d00
x-ms-ests-server: 2.1.24503.7 - JPWLR1 ProdSlices
x-ms-srs: 1.P

{"user_code":"OTD8DLVHP","device_code":"OBgABIQEAAAAdDD...","verification_uri":"https://login.microsoft.com/device","expires_in":900,"interval":5,"message":"To sign in, use a..."}

Method 1 - Step 2:

HTTP
POST /common/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/8.13.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 1096

client_id=3caf90da-c45a-4a78-9fd1-f7aa22fca3b6&device_code=OBgABIQEAAAAdDD...&grant_type=urn:ietf:params:oauth:grant-type:device_code



HTTP/1.1 400 Bad Request
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
x-ms-clientdata: e|28000||microsoftonline.com|none
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
x-ms-request-id: d4132094-5c4e-4431-98bc-59a1a96a1600
x-ms-ests-server: 2.1.24503.7 - SEASLR1 ProdSlices
x-ms-srs: 1.P

{"error":"invalid_request","error_description":"AADSTS28000: Provided value for the input parameter scope is not valid because it contains more than one resource. Scope https://graph.microsoft.com/User.Read https://outlook.office.com/SMTP.Send is not valid. Trace ID: d4132094-5c4e-4431-98bc-59a1a96a1600 Correlation ID: c785b83b-aa5d-4721-abe6-16ea5eec257e Timestamp: 2026-06-09 01:57:26Z","error_codes":[28000],"timestamp":"2026-06-09 01:57:26Z","trace_id":"d4132094-5c4e-4431-98bc-59a1a96a1600","correlation_id":"c785b83b-aa5d-4721-abe6-16ea5eec257e"}

Method 1 cannot achieve the three targets at the same time.

Method 2:

HTTP
POST /common/oauth2/v2.0/devicecode HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/8.13.0
Accept: */*
Content-Length: 127
Content-Type: application/x-www-form-urlencoded

client_id=3caf90da-c45a-4a78-9fd1-f7aa22fca3b6&scope=openid profile email offline_access https://outlook.office.com/SMTP.Send

Then decode the id_token and use preferred_username as the SMTP XOAUTH2 username.

According to Microsoft documentation, preferred_username is mutable and suitable for display or username hints. Therefore we cannot safely use preferred_username as the user= value in SMTP AUTH XOAUTH2.

Method 3:

Method 3 Step 1:

HTTP
POST /common/oauth2/v2.0/devicecode HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/7.83.1
Accept: */*
Content-Length: 114
Content-Type: application/x-www-form-urlencoded
Connection: close
client_id=3caf90da-c45a-4a78-9fd1-f7aa22fca3b6&scope=offline_access%20https%3A%2F%2Foutlook.office.com%2FSMTP.Send

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 1271
{"user_code":"NJKJHTJZP","device_code":"NBgABIQ...","verification_uri":"https://login.microsoft.com/device","expires_in":900,"interval":5}

Method 3 Step 2:

HTTP
POST /common/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/7.83.1
Accept: */*
Content-Length: 1118
Content-Type: application/x-www-form-urlencoded
Connection: close
client_id=3caf90da-c45a-4a78-9fd1-f7aa22fca3b6&device_code=NBgABIQ...&grant_type=urn:ietf:params:oauth:grant-type:device_code

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 1940
{"token_type":"Bearer","scope":"https://outlook.office.com/SMTP.Send","expires_in":3599,"ext_expires_in":3599,"access_token":"EwAIBOl...","refresh_token":"M.C554_BL..."}

Method 3 Step 3:

HTTP
POST /common/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/7.83.1
Accept: */*
Content-Length: 555
Content-Type: application/x-www-form-urlencoded
Connection: close
client_id=3caf90da-c45a-4a78-9fd1-f7aa22fca3b6&grant_type=refresh_token&refresh_token=M.C554_BL..&scope=https%3A%2F%2Fgraph.microsoft.com%2FUser.Read

HTTP/1.1 400 Bad Request
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 601
{"error":"invalid_grant","error_description":"AADSTS70000: The request was denied because one or more scopes requested are unauthorized or expired. The user must first sign in and grant the client application access to the requested scope. Trace ID: 2867f178-e432-4702-afbe-fef568191e00 Correlation ID: c13dbba2-e84e-4019-b3e3-4824126fe498 Timestamp: 2026-06-27 08:55:30Z","error_codes":[70000],"timestamp":"2026-06-27 08:55:30Z","trace_id":"2867f178-e432-4702-afbe-fef568191e00","correlation_id":"c13dbba2-e84e-4019-b3e3-4824126fe498","error_uri":"https://login.microsoftonline.com/error?code=70000"}

Method 3 also cannot achieve the three targets at the same time.

Method 4:

Method 4 - Step 1:

HTTP
POST /common/oauth2/v2.0/devicecode HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/7.83.1
Accept: */*
Content-Length: 162
Content-Type: application/x-www-form-urlencoded
Connection: close

client_id=8523e5e3-dcd1-4e56-8d32-15cdf1cb458d&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2FUser.Read%20https%3A%2F%2Foutlook.office.com%2FSMTP.Send

HTTP/1.1 200 OK
Cache-Control: no-store, no-cache
Pragma: no-cache
Connection: close
Content-Length: 1271

{"user_code":"HA43XWQT8","device_code":"HBgABIQ...","verification_uri":"https://login.microsoft.com/device","expires_in":900,"interval":5}

Method 4 - Step 2:

HTTP
POST /common/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
User-Agent: curl/7.83.1
Accept: */*
Content-Length: 1169
Content-Type: application/x-www-form-urlencoded
Connection: close

grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=HBgABIQ...&client_id=8523e5e3-dcd1-4e56-8d32-15cdf1cb458d&scope=https%3A%2F%2Foutlook.office.com%2FSMTP.Send


HTTP/1.1 400 Bad Request
Cache-Control: no-store, no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Connection: close
Content-Length: 570

{"error":"invalid_scope","error_description":"AADSTS70011: The provided value for the input parameter 'scope' is not valid. One or more scopes in 'offline_access https://graph.microsoft.com/User.Read https://outlook.office.com/SMTP.Send' are not compatible with each other. Trace ID: e57c0b2a-3207-4bc6-a0f1-ff4d58b00c00 Correlation ID: c3384118-f3d8-47eb-8777-2b9c767584ab Timestamp: 2026-06-29 03:42:18Z","error_codes":[70011],"timestamp":"2026-06-29 03:42:18Z","trace_id":"e57c0b2a-3207-4bc6-a0f1-ff4d58b00c00","correlation_id":"c3384118-f3d8-47eb-8777-2b9c767584ab"}

So Method 4 also failed.

Summary:

All three suggested methods failed to achieve the following three targets at the same time:

Targets 1: Obtain an access token that can be used to send email through SMTP AUTH XOAUTH2.

Targets 2: Obtain the correct user name that should be used in the user= field of the SMTP AUTH XOAUTH2 SASL string.

Targets 3: Require the end user to complete consent only one time in a web browser.

Questions:

  1. Does Microsoft officially support achieving these three targets at the same time for a limited-input device using OAuth 2.0 Device Code Flow?
  2. If yes, please provide the exact official HTTP request sequence.
  3. If the three targets cannot be achieved at the same time, please clearly confirm that limitation and provide the Microsoft-recommended product design for a limited-input printer that supports SMTP AUTH XOAUTH2 and POP3 AUTH XOAUTH2.
Microsoft Security | Microsoft Entra | Microsoft Entra ID
0 comments No comments

Answer accepted by question author
Alex Burlachenko 25,285 Reputation points MVP Volunteer Moderator
2026-06-30T09:48:43.2033333+00:00

hi QA1 & thx for sharing urs issue here at Q&A portal,

U hit a real OAuth limitation here. Microsoft Entra v2 tokens are single-audience. U can’t request https://graph.microsoft.com/User.Read and https://outlook.office.com/SMTP.Send in the same device-code request. That’s why AADSTS28000 / AADSTS70011 happens. Graph and Exchange/Outlook are different resources. MS says SMTP XOAUTH2 uses the Exchange/Outlook scope https://outlook.office.com/SMTP.Send, and the XOAUTH2 string uses the mailbox username/email in user=.

So if u need a reliable mailbox address from Graph and also an SMTP token, u need two resource tokens. That usually means either prior admin consent for both resources, or a second consent step. Without that, a refresh token obtained only for SMTP won’t magically allow Graph User.Read. That’s exactly what ur Method 3 proved.

Using preferred_username from id_token is a practical shortcut, but I agree it’s not a perfect source of truth. It’s fine for display/hinting, not a hard guarantee for the mailbox SMTP address. The clean product design is: during device setup, ask the user/admin to enter or confirm the mailbox email address once, then use Device Code Flow only for offline_access https://outlook.office.com/SMTP.Send. Store the refresh token and the confirmed SMTP username. For a printer, that’s probably the most realistic SMTP AUTH XOAUTH2 design.

If u must discover the mailbox automatically, use Graph, but then u need Graph consent too. That can be admin-preconsented, then the device can redeem tokens for Graph and Exchange separately.

https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth

https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-device-code

So I assume no, I don’t think Microsoft supports all 3 targets in one pure end-user device-code consent flow if u require Graph as the reliable username source and SMTP as the mail token. Use confirmed mailbox input, admin pre-consent, or switch to Graph sendMail instead of SMTP.

rgds,

Alex

&

If my answer was helpful pls mark it and additional thx if u follow me at Q&A portal

and at my blog https://ctrlaltdel.blog/

 

Was this answer helpful?

1 person found this answer helpful.
0 comments No comments

0 additional answers

Sort by: Oldest

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.