-2

I have an application with a NodeJS backend and a React frontend, and I want to implement Azure SSO for it. Since the frontend is served by the backend, users who want to log in to the application are redirected by the backend to the login page on the frontend. When users click on the relevant button on the login page, the Azure authentication page should open, and after login, they should be redirected back to my application. However, I am getting an error on the API side as shown below.

Access to XMLHttpRequest at 'https://login.microsoftonline.com/xxx/oauth2/v2.0/authorize?client_id={clientid}1&response_type=code&redirect_uri=http:%2F%2Flocalhost:3000%2Fauth%2Fcallback&response_mode=query&scope=https:%2F%2Fgraph.microsoft.com%2F.default+offline_access' (redirected from 'http://localhost:3000/api/auth/sso-login') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

my api code is

const params = new URLSearchParams({
    client_id: CLIENT_ID,
    response_type: 'code',
    redirect_uri: REDIRECT_URI,
    response_mode: 'query',
    scope: 'https://graph.microsoft.com/.default offline_access'
  });

  res.redirect(`${authorizeUrl}?${params.toString()}`);

i created a simple nodejs app with same logic without frontend, it worked without problem.

app.get('/login', (req, res) => {
  const params = new URLSearchParams({
    client_id: CLIENT_ID,
    response_type: 'code',
    redirect_uri: REDIRECT_URI,
    response_mode: 'query',
    scope: 'https://graph.microsoft.com/.default offline_access'
  });

  res.redirect(`${authorizeUrl}?${params.toString()}`);
});

app.get('/auth/callback', async (req, res) => {
  const { code } = req.query;

  if (!code) {
    return res.status(400).send('Authorization code not found.');
  }

  try {
    const response = await axios.post(tokenUrl, new URLSearchParams({
      client_id: CLIENT_ID,
      scope: 'https://graph.microsoft.com/.default',
      code,
      redirect_uri: REDIRECT_URI,
      grant_type: 'authorization_code',
      client_secret: CLIENT_SECRET
    }));

    const accessToken = response.data.access_token;
    res.send(`Access Token: ${accessToken}`);
  } catch (error) {
    res.status(500).send(`Error exchanging code: ${error.message}`);
  }
});```
 
6
  • 1
    Seems like instead of following the redirect you’re trying to fetch it on the frontend. However, you haven’t added a minimal reproducible example of the frontend code that actually produces this error. Commented Oct 27, 2024 at 0:38
  • @osmnfdrcn Have you added cors in the backend code? Can you share it in the question? Commented Oct 27, 2024 at 0:51
  • @osmnfdrcn Can you provide your GitHub repo? Commented Oct 27, 2024 at 7:06
  • you need to add cors for the nodejs code Commented Oct 27, 2024 at 14:05
  • @osmnfdrcn Try this GitHub repository to fix the cors issue in the backend(nodejs). Frontend output. Commented Oct 27, 2024 at 17:35

1 Answer 1

0

I fixed the issue by adding CORS to the backend (Node.js) code. Users who want to log in to the application are now successfully redirected by the backend to the login page on the frontend, and the access token is retrieved.

Here is the complete code in this GitHub repository.

backend/index.js :

const express = require('express');
const axios = require('axios');
const cors = require('cors');
const dotenv = require('dotenv');

dotenv.config();

const app = express();
app.use(cors());
app.use(express.json());
const tokenUrl = `https://login.microsoftonline.com/${process.env.TENANT_ID}/oauth2/v2.0/token`;

app.get('/api/auth/sso-login', (req, res) => {
  const params = new URLSearchParams({
    client_id: process.env.CLIENT_ID,
    response_type: 'code',
    redirect_uri: process.env.REDIRECT_URI,
    response_mode: 'query',
    scope: 'https://graph.microsoft.com/.default offline_access',
  });

  const loginUrl = `https://login.microsoftonline.com/${process.env.TENANT_ID}/oauth2/v2.0/authorize?${params.toString()}`;
  res.redirect(loginUrl);
});

app.post('/api/auth/exchange-token', async (req, res) => {
  const { code } = req.body;
  if (!code) {
    return res.status(400).json({ error: 'Authorization code not provided' });
  }
  try {
    const response = await axios.post(tokenUrl, new URLSearchParams({
      client_id: process.env.CLIENT_ID,
      scope: 'https://graph.microsoft.com/.default',
      code,
      redirect_uri: process.env.REDIRECT_URI,
      grant_type: 'authorization_code',
      client_secret: process.env.CLIENT_SECRET,
    }));
    const accessToken = response.data.access_token;
    res.json({ accessToken });
  } catch (error) {
    res.status(500).json({ error: `Error exchanging code: ${error.message}` });
  }
});

const PORT = 4000;
app.listen(PORT, () => {
  console.log(`Backend running on http://localhost:${PORT}`);
});

.env :

CLIENT_ID=<Client_ID>
CLIENT_SECRET=<Client_Secret>
TENANT_ID=<tenant_ID>
REDIRECT_URI=http://localhost:3000/auth/callback

frontend/Login.js :

import React from 'react';

const Login = () => {
  const handleLogin = () => {
    window.location.href = `${process.env.REACT_APP_BACKEND_URL}/api/auth/sso-login`;
  };
  return (
    <div>
      <h2>Login Page</h2>
      <button onClick={handleLogin}>Login with Azure</button>
    </div>
  );
};
export default Login;

frontend/.env :

REACT_APP_CLIENT_ID=<client_ID>
REACT_APP_TENANT_ID=<tenant_ID>
REACT_APP_REDIRECT_URI=http://localhost:3000/auth/callback
REACT_APP_BACKEND_URL=http://localhost:4000

I have added the below URL in the Azure AD app's redirect URI under Web as shown below.

http://localhost:3000/auth/callback

enter image description here

backend Output :

I successfully ran the backend (Node.js) application. When I opened the URL below in the browser, it redirected me to the login page, and I logged in with my account as shown below:

http://localhost:4000/api/auth/sso-login

enter image description here

After logging in, I received the authorization code as shown below:

enter image description here

I copied the authorization code and used it in the POST request, as shown below.

enter image description here

I sent a POST request with the authorization_code and received the access token as shown below.

http://localhost:4000/api/auth/exchange-token
{
  "code": "<authorization_code>"
}

enter image description here

frontend Output :

I successfully ran the frontend (React.js) application and logged in using the Login with Azure button.

enter image description here

enter image description here

After logging in, I retrieved the access token as shown below.

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.