Microsoft DeviceCode Authentication returning 'invalid-request' error during login

IzMichael 1 Reputation point
2021-10-13T03:01:39.52+00:00

Within the Electron app I'm creating, I'm trying to authenticate a personal Microsoft account and obtain the access token and refresh token using the DeviceCode method. (Using these instructions) I am able to successfully retrieve the DeviceCode needed to login using the following:

var bod1 = new URLSearchParams();
    bod1.append('client_id', 'CLIENT ID');
    bod1.append('scope', 'offline_access XboxLive.signin');

var req1 = await fetch('https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: bod1
}).then(res => {return res.json()});

The above request returns something similar to:

{
    "user_code": "B6N9D34T",
    "device_code": "DEVICE ID",
    "verification_uri": "https://www.microsoft.com/link",
    "expires_in": 900,
    "interval": 5,
    "message": "To sign in, use a web browser to open the page https://www.microsoft.com/link and enter the code B6N9D34T to authenticate."
}

I send the user to https://www.microsoft.com/link and they input the user_code and they sign in as normal. Following Step 2 I run the following request every 5 seconds until the user finished logging in using the code and URL above:

var bod2 = new URLSearchParams();
    bod2.append('client_id', '6fbc920e-8515-414c-ac36-296b084e6fb2');
    bod2.append('grant_type', 'urn:ietf:params:oauth:grant-type:device_code');
    bod2.append('device_code', req1.device_code);

while (done2 == false) {
    await fetch('https://login.microsoftonline.com/consumers/oauth2/v2.0/token', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: bod2
        })
        .then(res => {
            return res.json()
        })
        .then(result => {
            if (!result.error) {
                req2 = result;
                done2 = true;
            }
        });
};

which is supposed to return something similar to the following JSON (once the user completes the login using the code that I gave earlier):

{
    "token_type": "Bearer",
    "scope": "offline_access XboxLive.signin",
    "expires_in": 3599,
    "access_token": "TOKEN",
    "refresh_token": "OTHER TOKEN",
    "id_token": "OTHER OTHER TOKEN"
}

But instead it returns this:

{
    "error":"invalid_request",
    "error_description":"AADSTS90023: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.\r\nTrace ID: 97afe241-4a2f-4336-9f41-ab8343120700\r\nCorrelation ID: 9c05a420-ae3a-4031-9b8a-b002d72c49b1\r\nTimestamp: 2021-10-03 01:39:18Z",
    "error_codes":[90023],
    "timestamp":"2021-10-03 01:39:18Z",
    "trace_id":"97afe241-4a2f-4336-9f41-ab8343120700",
    "correlation_id":"9c05a420-ae3a-4031-9b8a-b002d72c49b1"
}

and I can't figure out why.
I should note that I have tried doing this just using Node without Electron, and it works perfectly, but not when running in an Electron app.

Microsoft Security Microsoft Entra Microsoft Entra ID
{count} votes

Your answer

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