HTTP status code 400 | Attempted to reach: https://login.microsoftonline.com/common/oauth2/v2.0/token
See original GitHub issueCore Library
MSAL Node (@azure/msal-node)
Core Library Version
1.12.1
Wrapper Library
Not Applicable
Wrapper Library Version
na
Description
.acquireTokenByCode()
results in an http status 400
I’m creating an OAuth flow with Vercel/Nextjs serverless functions and this error has plagued me for a week. The auth code flow works fine using .getAuthCodeUrl()
.
Testing a deployment build on Vercel returned the 400 error. Making a fetch request directly to the endpoint also resulted in a 400 error.
I downloaded the quickstart code from the Azure dashboard and it works perfectly fine. This tells me it’s not a problem with my machine or Azure app registration, but probably a problem in my configuration and usage of the library.
I’ve basically copied that quickstart code into serverless functions and now it doesn’t work. Please let me know how to debug this issue or if I’ve made a mistake in my code 👍
Error Message
ClientAuthError: network_error: Network request failed. Please check network trace to determine root cause. | Fetch client threw: Error: HTTP status code 400 | Attempted to reach: https://login.microsoftonline.com/common/oauth2/v2.0/token
at ClientAuthError.AuthError [as constructor] (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:500:24)
at new ClientAuthError (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:802:28)
at Function.ClientAuthError.createNetworkError (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:845:16)
at NetworkManager.<anonymous> (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:3418:51)
at step (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:79:23)
at Object.throw (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:60:53)
at rejected (C:\Development\rememberly-ui\node_modules@azure\msal-common\dist\index.cjs.js:51:65)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
errorCode: ‘network_error’,
errorMessage: ‘Network request failed. Please check network trace to determine root cause. | Fetch client threw: Error: HTTP status code 400 | Attempted to reach: https://login.microsoftonline.com/common/oauth2/v2.0/token’,
subError: ‘’
}
Msal Logs
[Thu, 04 Aug 2022 01:19:29 GMT] : @azure/msal-node@1.12.1 : Info - acquireTokenByCode called [Thu, 04 Aug 2022 01:19:29 GMT] : @azure/msal-node@1.12.1 : Verbose - initializeRequestScopes called[Thu, 04 Aug 2022 01:19:29 GMT] : [14fd4f2e-9a49-4738-b9ae-0a5f6f83186a] : @azure/msal-node@1.12.1 : Verbose - buildOauthClientConfiguration called [Thu, 04 Aug 2022 01:19:29 GMT] : [14fd4f2e-9a49-4738-b9ae-0a5f6f83186a] : @azure/msal-node@1.12.1 : Verbose - building oauth client configuration with the authority: https://login.microsoftonline.com/common [Thu, 04 Aug 2022 01:19:29 GMT] : [14fd4f2e-9a49-4738-b9ae-0a5f6f83186a] : @azure/msal-node@1.12.1 : Verbose - createAuthority called [Thu, 04 Aug 2022 01:19:29 GMT] : [14fd4f2e-9a49-4738-b9ae-0a5f6f83186a] : @azure/msal-node@1.12.1 : Verbose - Auth code client created [Thu, 04 Aug 2022 01:19:29 GMT] : [14fd4f2e-9a49-4738-b9ae-0a5f6f83186a] : @azure/msal-common@7.3.0 : Info - in acquireToken call
MSAL Configuration
const clientConfig = {
auth: {
clientId: process.env.AZURE_CLIENT_ID,
authority: 'https://login.microsoftonline.com/common',
clientSecret: process.env.AZURE_CLIENT_SECRET
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose
}
}
};
Relevant Code Snippets
~~ _utils.js ~~
const msal = require('@azure/msal-node');
const clientConfig = {
auth: {
clientId: process.env.AZURE_CLIENT_ID,
authority: 'https://login.microsoftonline.com/common',
clientSecret: process.env.AZURE_CLIENT_SECRET
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose
}
}
};
export const clientApplication = new msal.ConfidentialClientApplication(clientConfig)
~~~~~~
~~ exchange-auth-code.js ~~
import { getURL } from '@/utils/helpers';
import { clientApplication } from './_utils';
const exchangeOutlookAuthCode = async (req, res) => {
const code = req.body.code; // code is passed in from POST request on the frontend
const redirectUri = getURL() + '/api/outlook/exchange-auth-code';
const tokenRequest = {
code,
redirectUri,
scopes: ['user.read']
};
await clientApplication
.acquireTokenByCode(tokenRequest)
.then((response) => {
console.log('response: ', response);
})
.catch((err) => {
console.error(err);
});
};
export default exchangeOutlookAuthCode;
~~~~~~
~~ quickstart code from Azure, this code works ~~
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
const express = require("express");
const msal = require('@azure/msal-node');
const SERVER_PORT = process.env.PORT || 3000;
const REDIRECT_URI = "http://localhost:3000/redirect";
// Before running the sample, you will need to replace the values in the config,
// including the clientSecret
const config = {
auth: {
clientId: "*******",
authority: "https://login.microsoftonline.com/common",
clientSecret: "*******"
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
// Create msal application object
const pca = new msal.ConfidentialClientApplication(config);
// Create Express App and Routes
const app = express();
app.get('/', (req, res) => {
const authCodeUrlParameters = {
scopes: ["user.read"],
redirectUri: REDIRECT_URI,
};
// get url to sign user in and consent to scopes needed for application
pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
res.redirect(response);
}).catch((error) => console.log(JSON.stringify(error)));
});
app.get('/redirect', (req, res) => {
const tokenRequest = {
code: req.query.code,
scopes: ["user.read"],
redirectUri: REDIRECT_URI,
};
console.log(pca.storage.cache)
pca.acquireTokenByCode(tokenRequest).then((response) => {
console.log("\nResponse: \n:", response);
res.sendStatus(200);
}).catch((error) => {
console.log(error);
res.status(500).send(error);
});
});
app.listen(SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on port ${SERVER_PORT}!`))
Reproduction Steps
- create post request to
http://localhost;3000/api/outlook/exchange-auth-code
with the auth code as a value in the body :{code: auth_code}
- code returns the error listed above
Error: HTTP status code 400
Expected Behavior
Expected to return access token and refresh token
Identity Provider
Azure AD / MSA
Browsers Affected (Select all that apply)
None (Server)
Regression
No response
Source
External (Customer)
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:6 (3 by maintainers)
Top GitHub Comments
We’ve seen a very similar-looking issue, though it’s hard to say if it’s the same without more info.
In our case, it’s in an Electron app, and the error only seems to happen to a certain customer who is using ADFS. The renderer (browser) process performs interactive auth, and when the redirect URI is hit, it sends the auth code to the main (Node.js) process, which calls
acquireTokenByCode()
. ThataquireTokenByCode()
call fails with an HTTP 400 ClientAuthError.We were able to dig into the error further and determine the actual 400 error is an “invalid_grant” error with a message of: “AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access ‘<REDACTED>’”. Usually MFA is handled while obtaining the auth code, so we’re still not sure what’s going wrong here.
If you debug into the MSAL library code itself you may be able to find the real underlying HTTP 400 error which is being swallowed. (See this issue)
@LodenH16 Interesting, glad to hear its now working.