8

I am making an application in React and use the "react-aad-msal" library (https://www.npmjs.com/package/react-aad-msal), which is authenticated and authorized using AzureAD and then receives data (list tasks) from API (as I took this example https://github.com/Azure-Samples/ms-identity-javascript-angular-spa-dotnetcore-webapi-roles-groups/tree/master/chapter2/TodoListAPI). I have the following components: authProvider.js, TodoConstants.js, TodoActions.js, TodoReducer.js, TodoContainer.js, TodoSaga.js. When I added const token = await authProvider.getAccessToken () to request data from the API in TodoSaga.js, I started getting an error: Unhandled Rejection (ClientAuthError): User login is required. For silent calls, request must contain either sid or login_hint. If you add loginHint: "myMail@domain.com" to authProvider.js in authenticationParameters, then it starts working correctly and offers to go directly to the authentication stage, but how to specify loginHint or sid correctly is not clear. Please tell me how to get loginHint or sid correctly in this situation? And which parameter is preferable?

authProvider.js

import { MsalAuthProvider, LoginType } from "react-aad-msal";
import { Logger, LogLevel } from "msal";

const config = {
  auth: {
    clientId: "xxxx-xxxx-xxxx-xxxx",
    authority:
      "https://login.microsoftonline.com/yyyy-yyyy-yyyy-yyyy",
    validateAuthority: true,
    redirectUri: "http://localhost:3000",
    postLogoutRedirectUri: "http://localhost:3000",
    navigateToLoginRequestUrl: true,
  },
  cache: {
    cacheLocation: "localStorage",
    storeAuthStateInCookie: true,
  },
};

const authenticationParameters = {
  scopes: [
    "openid",
    "profile",
    "api://iiii-iiii-iiii-iiii/access_as_user",
  ],
  // loginHint: loginHint, <---- How to get it correctly?
  // sid: sid, <---- How to get it correctly?
};

const options = {
  loginType: LoginType.Popup,
  tokenRefreshUri: window.location.origin + "/auth.html",
};

export const authProvider = new MsalAuthProvider(
  config,
  authenticationParameters,
  options
);

TodoConstants.js

export const TODODATASOURCE_API_CALL_REQUEST = "TODODATASOURCE_API_CALL_REQUEST";
export const TODODATASOURCE_API_CALL_SUCCESS = "TODODATASOURCE_API_CALL_SUCCESS";
export const TODODATASOURCE_API_CALL_FAILURE = "TODODATASOURCE_API_CALL_FAILURE";

TodoActions.js

import * as types from "./TodoConstants";

export const fetchTodoDataSourceRequest = () => {
  return {
    type: types.TODODATASOURCE_API_CALL_REQUEST
  };
};

export const fetchTodoDataSourceSuccess = response => {
  return {
    type: types.TODODATASOURCE_API_CALL_SUCCESS,
    data: response,
  };
};

export const fetchTodoDataSourceFail = () => {
  return {
    type: types.TODODATASOURCE_API_CALL_FAILURE
  };
};

TodoReducer.js

import * as types from "./TodoConstants";

const initialState = {
  fetching: false,
  data: null,
  error: null,
};

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case types.TODODATASOURCE_API_CALL_REQUEST:
      return { ...state, fetching: true, error: null };
    case types.TODODATASOURCE_API_CALL_SUCCESS:
      return {
        ...state,
        fetching: false,
        data: action.data,
      };
    case types.TODODATASOURCE_API_CALL_FAILURE:
      return {
        ...state,
        fetching: false,
        data: null,
        error: action.error
      };

    default:
      return state;
  }
}

TodoContainer.js

import React from "react";
import TodoView from "../../views/TodoView";
import { connect } from "react-redux";
import * as actions from "./TodoActions";
// import { bindActionCreators } from "redux";
import { bindActionCreators } from "redux";

class TodoDataSourceContainer extends React.PureComponent {
  componentDidMount() {
    this.props.fetchTodoDataSourceRequest();
  }
  render() {
    return (
      <React.Fragment>
        <TodoDataSourceView {...this.props} />
      </React.Fragment>
    );
  }
}

const mapStateToProps = ({
  TodoDataSourceContainerReducerState: { fetching, data, error},
}) => {
  return {
    fetching: fetching,
    data: data,
    error: error,
  };
};

const mapDispatchToProps = (dispatch) => {
  const {
    fetchTodoDataSourceRequest: fetchTodoDataSourceRequest,
  } = bindActionCreators(actions, dispatch);
  return {
    fetchTodoDataSourceRequest: fetchTodoDataSourceRequest,
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoDataSourceContainer);

TodoSaga.js

import { takeLatest, call, put } from "redux-saga/effects";
import * as types from "./TodoConstants";
import * as actions from "./TodoActions";
import { authProvider } from "../../../utils/Auth/authProvider";

const request = async (url) => {
  const token = await authProvider.getAccessToken(); // <---- After adding this, an error appears and the need for loginHint or sid

  const response = await fetch(url, {
    method: "GET",
    headers: {
      Authorization: "Bearer " + token.accessToken,
      "Content-Type": "application/json",
    },
  });

  if (response.ok) {
    let result = await response.json();
    return result;
  } else {
    alert("Error HTTP: " + response.status);
  }
};

export default function* watcherSaga() {
  yield takeLatest(types.TODODATASOURCE_API_CALL_REQUEST, workerSaga);
}

function* workerSaga() {
  try {
    const response = yield request("https://localhost:44351/api/todolist");
    yield put(actions.fetchTodoDataSourceSuccess(response));
  } catch (error) {
    yield put(actions.fetchTodoDataSourceFail(error));
  }
}

enter image description here

Dan Bonachea
  • 2,408
  • 5
  • 16
  • 31
user13572001
  • 81
  • 1
  • 3

1 Answers1

0

Reading https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow :

You can use this parameter to pre-fill the username and email address field of the sign-in page for the user. Apps can use this parameter during reauthentication, after already extracting the login_hint optional claim from an earlier sign-in.

So just set login_hint to your-mail@domain.com or your company's usual e-mail pattern.

barbara.post
  • 1,581
  • 16
  • 27