I am trying to build an auth server that logs in the user to other applications with the user's Microsoft account. I have created an app in Azure AD and integrated it with the backend. The following is the flow of the application,
- GET request to
/auth/sign
endpoint returns the Auth URL to the client generating a csrf_token which is stored in a session and a state parameter that is sent as a query param of Auth URL. - With the auth URL
https://login.microsoft.com/...
a GET request is sent to Azure AD from the client. - Once the user is logged in successfully with the credentials, a POST request is sent to the
REDIRECT_URI
configured in the Azure AD portalhttp://localhost:3000/auth/redirect
in this case.
I get no error when I directly hit the endpoints in the browser. That is, http://localhost:3000/auth/signin
returns the auth URL which is then used to get the details of the user through REDIRECT_URL
.
When the frontend comes into action (Angular), I get the error that csrf_token is not matching as the session is undefined. I tried logging MemoryStore and the session was not expired and present in the store. Now, I have to validate the csrf_token in the request from the Azure AD.
Below is the pictorial representation of the issue I face.
The auth.js
file for sign in,
router.get('/auth/signin', async function (req, res, next) {
req.session.csrfToken = cryptoProvider.createNewGuid(); // Generate csrf and store in the session
const state = cryptoProvider.base64Encode(
JSON.stringify({
csrfToken: req.session.csrfToken,
})
);
const authCodeUrlRequestParams = {
state: state,
scopes: [],
};
const authCodeRequestParams = {
scopes: [],
};
return res.json({authUrl: await redirectToAuthCodeUrl(req, res, next, authCodeUrlRequestParams, authCodeRequestParams)});
});
async function redirectToAuthCodeUrl(req, res, next, authCodeUrlRequestParams, authCodeRequestParams) {
// Generate PKCE Codes before starting the authorization flow
const { verifier, challenge } = await cryptoProvider.generatePkceCodes();
// Set generated PKCE codes and method as session vars
req.session.pkceCodes = {
challengeMethod: 'S256',
verifier: verifier,
challenge: challenge,
};
req.session.authCodeUrlRequest = {
redirectUri: REDIRECT_URI,
responseMode: 'form_post', // recommended for confidential clients
codeChallenge: req.session.pkceCodes.challenge,
codeChallengeMethod: req.session.pkceCodes.challengeMethod,
...authCodeUrlRequestParams,
};
req.session.authCodeRequest = {
redirectUri: REDIRECT_URI,
code: "",
...authCodeRequestParams,
};
try {
const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
return authCodeUrlResponse;
} catch (error) {
next(error);
}
};
The /auth/redirect
endpoint,
router.post('/auth/redirect', async function (req, res, next) {
console.log(req);
if (req.body.state) {
const state = JSON.parse(cryptoProvider.base64Decode(req.body.state));
// check if csrfToken matches
if (state.csrfToken === req.session.csrfToken) {
req.session.authCodeRequest.code = req.body.code; // authZ code
req.session.authCodeRequest.codeVerifier = req.session.pkceCodes.verifier // PKCE Code Verifier
try {
const tokenResponse = await msalInstance.acquireTokenByCode(req.session.authCodeRequest);
req.session.accessToken = tokenResponse.accessToken;
req.session.idToken = tokenResponse.idToken;
req.session.account = tokenResponse.account;
req.session.isAuthenticated = true;
return res.json({ session: req.session });
} catch (error) {
next(error);
}
} else {
next(new Error('csrf token does not match'));
}
} else {
next(new Error('state is missing'));
}
});
Kindly help me in getting the details of the user from Azure AD and redirect it to the client end.
TIA