How to get user profile details using Azure AD - reactjs

I am using react-aad-masl module to integrate Microsoft SSO in my react application. I am able to redirect my user to Microsoft login page and after that its coming back to my page with token. After that its only returning accountInfo that contain User name and email ID. I have a requirement to get user other details as well like ID, first name, last name, Group, etc.
These all details will come through this Azure AD MASL or i need to do Graph API call?
Below is my implementation
//authProvider.js
import { MsalAuthProvider, LoginType } from 'react-aad-msal';
import { Logger, LogLevel } from "msal";
// Msal Configurations
const config = {
auth: {
authority: 'https://login.microsoftonline.com/*********',
clientId: '*************',
redirectUri: 'http://localhost:3000/'
},
// Enable logging of MSAL events for easier troubleshooting.
// This should be disabled in production builds.
system: {
logger: new Logger(
(logLevel, message, containsPii) => {
console.log("[MSAL]", message);
},
{
level: LogLevel.Verbose,
piiLoggingEnabled: false
}
)
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: true
}
};
// Authentication Parameters
const authenticationParameters = {
scopes: [
'user.read',
'profile',
'openid'
//'profile.read',
// 'User.Read.All',
// 'Group.Read.All',
// 'User.ReadBasic.All',
// 'Group.Read'
]
}
// Options
const options = {
loginType: LoginType.Redirect,
tokenRefreshUri: window.location.origin + '/auth.html'
}
export const authProvider = new MsalAuthProvider(config, authenticationParameters, options)
//APP.js
<AzureAD provider={authProvider} forceLogin={false}>
{(abc) => {
console.log('>>>>>>>>>>>>...', abc);
props.setAccountInfo(abc.accountInfo.account);
return <AppRouter />
}}
</AzureAD>
Here in abc i am getting below information
Please help me in this

You need to configure the optional claims in the application token configuration for First Name, Last Name.
Please go through the documentation for more information
Regarding the group information please check this document

Related

Setting up Azure B2C with React

I am trying to configure my react/.NET 5.0 application to work with Azure B2C. I have everything set up , I have tried to run this against an MVC application and I get the login screen. But for some reason, when I try to redirect from a react page, I keep getting the same error. There appears to be almost no real good documentation for this as well. This is my authConfig file.
export const msalConfig = {
auth: {
clientId: process.env.REACT_APP_ADB2C_CLIENT_ID
, authority: process.env.REACT_APP_ADB2C_AUTHORITY
, knownAuthorities: [process.env.REACT_APP_KNOWN_AUTH]
, clientSecret: process.env.REACT_APP_CLIENT_SECRET
, reponseType: 'code'
},
cache: {
cacheLocation: 'sessionStorage'
,storeAuthStateInCoolie: false
}
};
const b2cPolicies = {
name: {
signUpSignIn: "B2C_1_cp_signin_up"
, forgotPassword: "B2C_1_cp_forgot_pwd"
, editProfile: "B2C_1_cp_edit_profile"
},
authorities: {
signUpSignIn: {
authority: `https://${process.env.REACT_APP_TENANT_LOGIN}/${process.env.REACT_APP_TENANT}/${process.env.REACT_APP_SIGNUP_POLICY}`,
},
forgotPassword: {
authority: `https://${process.env.REACT_APP_TENANT_LOGIN}/${process.env.REACT_APP_TENANT}/${process.env.REACT_APP_FORGOT_POLICY}`,
},
editProfile: {
authority: `https://${process.env.REACT_APP_TENANT_LOGIN}/${process.env.REACT_APP_TENANT}/${process.env.REACT_APP_EDIT_POLICY}`
}
},
authorityDomain: process.env.REACT_APP_TENANT_LOGIN
}
export const loginRequest = {
scopes: ["openid", "profile"],
};
I keep running into this error when I click on the link to redirect.
Any help with this would be great.
The reply URL must begin with the scheme https. Please check if reply urls are configured correctly which must be same in azure portal and in code .
Check if the callback path is set to identity provider something like /signin-oidc for redirect url .(And make sure you have unique callback if multiple urls are used.
such as https://contoso.com/signin-oidc.
The CallbackPath is the path where server will redirect during authentication. It's automatically handled by the OIDC middleware itself, that means we can't control the logic by creating a new controller/action and set CallbackPath to it
If you have check marked id_token in portal, try redirecting to home page ,instead of api actions directly.
Change the cookies to be set as secure using this in start up class
services.Configure(options =>
{
options.CheckConsentNeeded = context => true;//add if consent needed
options.MinimumSameSitePolicy = SameSiteMode.None; // else try SameSiteMode.Lax;
options.Secure = CookieSecurePolicy.Always;
});
use Microsoft.AspNetCore.HttpOverrides; reference in startup.cs class, by including the nuget package.
Also check and Add > app.UseHttpsRedirection(); above app.authentication(); in startup configure method.
then try again.
If not try to set ProtocolMessage.RedirectUri to the HTTPS url
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
Configuration.Bind("AzureAdB2C", options);
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async ctx =>
{
/* Redirect Uri modified for https protocol */
ctx.ProtocolMessage.RedirectUri = urlWithHttps
}
}
});
Or you can pass login hint :Please refer this doc.
References:
Tutorial: Register an application - Azure AD B2C | Microsoft Docs
Configure authentication in a sample web application by using Azure Active Directory B2C | Microsoft Docs

What is the structure of the config file for Azure B2C Authetication using react app along with the Authority link structure?

I am trying to get the perfect structure of config and the authority url for my B2C auth application that will be integrated with Azure and React. I did get this structure for my config file and the auth link is specified as in the comments. but I am not able to get the popup screen and the error says that the authority link is invalid.
import { LogLevel } from "#azure/msal-browser";
/**
* To learn more about user flows, visit: https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-flow-overview
* To learn more about custom policies, visit: https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-overview
*/
const tenantName = "TenantName";
const signInPolicy = "Plicy_For_SignIn";
const applicationID = "CliendId";
const reactRedirectUri = "http://localhost:3000"; //RedirectURL
// Formatted as https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantguid or full tenant name including onmicrosoft.com}/{signuporinpolicyname}
const AuthorityUrl = `https://${tenantName}/tfp/${tenantName}/${signInPolicy}`;
/**
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md
*/
export const msalConfig = {
auth: {
clientId: applicationID,
authority: AuthorityUrl,
redirectUri: reactRedirectUri,
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
default:
return;
}
},
},
},
};
/**
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
*/
export const loginRequest = {
scopes: ["User.Read"],
};
After using the same and passing it to the root of the Index.js file by wrapping it with MsalProvider and calling the instance for a popup login is not working.
I am using the packages that are mentioned in the official documents #azure/msal-react and #azure/msal-browser
The Error that I am getting is a 400 followed by a message that says:
ClientAuthError: endpoints_resolution_error: Error: could not resolve endpoints. Please check network and try again. Detail: ClientConfigurationError: untrusted_authority: The provided authority is not a trusted authority. Please include this authority in the knownAuthorities config parameter.
I need some help on this!!
Thabk you!!
Here is an example authority URL, as per the guide here:
authority: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/Your-B2C-SignInOrSignUp-Policy-Id"
Your code has:
const tenantName = "TenantName";
const signInPolicy = "Plicy_For_SignIn";
const AuthorityUrl = https://${tenantName}/tfp/${tenantName}/${signInPolicy}
Which results into:
https://TenantName/tfp/TenantName/Plicy_For_SignIn -> that does not conform to the sample.
You need to make it follow this format:
authority: "https://contoso.b2clogin.com/contoso.onmicrosoft.com/Your-B2C-SignInOrSignUp-Policy-Id"
As follows:
const AuthorityUrl = https://${tenantName}.b2clogin.com/tfp/${tenantName}.onmicrosoft.com/${signInPolicy}

Cannot authenticate: Azure authentication in React app

I'm trying to set up Azure authentication from a React app following this tutorial:
https://learn.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-react
After setting up Azure and running it, I get this error:
ClientConfigurationError: url_parse_error: URL could not be parsed into appropriate segments. Given Error: Given url string: common/
Below is the configuration file 'authConfig.js'.
I don't know what I'm doing wrong as I'm doing this for the first time and I don't understand the error messages, nor do I find anything relevant in the docs other than what I've tried, changing the authority string.
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { LogLevel } from "#azure/msal-browser";
/**
* Configuration object to be passed to MSAL instance on creation.
* For a full list of MSAL.js configuration parameters, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md
*/
export const msalConfig = {
auth: {
clientId: "912fcdde-6306-4397-96ec-d7e24418d206",
// authority: "bde20525-a858-4726-a4c7-48bd8239499f",
// authority: "emtechdemo07052021.onmicrosoft.com",
authority: "common",
redirectUri: "http://localhost:3000"
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: true, // Set this to "true" if you are having issues on IE11 or Edge
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
}
}
}
}
};
/**
* Scopes you add here will be prompted for user consent during sign-in.
* By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.
* For more information about OIDC scopes, visit:
* https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
*/
export const loginRequest = {
scopes: ["User.Read"]
};
/**
* Add here the scopes to request when obtaining an access token for MS Graph API. For more information, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/resources-and-scopes.md
*/
export const graphConfig = {
graphMeEndpoint: "https://graph.microsoft.com"
};
Please try by changing the value of authority to:
https://login.microsoftonline.com/common
If you want to authenticate users against a specific tenant, please specify that tenant id or fully qualified tenant name instead of common. Something like:
https://login.microsoftonline.com/bde20525-a858-4726-a4c7-48bd8239499f
- OR -
https://login.microsoftonline.com/emtechdemo07052021.onmicrosoft.com
For more details, please see here (2nd bullet point which talks about the values for msalConfig section).

Redirect to same URL at client side after authentication from token server (identity server 4)

I am using Identity server 4 for user identity and token service. And my client application written in .Net core React template. Everything is working fine, however when end user hit the client side sub URL page (received from email), it is redirecting to STS identity server for authentication and return back to home page instead of to Sub page from where user hit the URL in the begging.
example when user hit client side URL (https://localhost:44309/bills)(which is received through email) it is going login page at (https://localhost:44318/Login) and after user authentication it is redirecting to (https://localhost:44309/Home) instead of (https://localhost:44309/bills).
I used Identity server 4 code written similar to below link
https://github.com/damienbod/IdentityServer4AspNetCoreIdentityTemplate/tree/master/content/StsServerIdentity
Identity server added client
{
"ClientId": "reactclient",
"ClientName": "React Client",
"Enabled": true,
"RequireClientSecret": false,
"EnableLocalLogin": true,
"RequireConsent": false,
"AllowedGrantTypes": [ "authorization_code", "hybrid", "client_credentials" ],
"RedirectUris": [ "https://localhost:44309/signin-oidc" ],
"PostLogoutRedirectUris": [ "https://localhost:44309/logout/callback" ],
"AccessTokenType": "Jwt",
"AllowAccessTokensViaBrowser": true,
//"UpdateAccessTokenClaimsOnRefresh": true,
"AllowOfflineAccess": true,
"AccessTokenLifetime": 14400,
"IdentityTokenLifetime": 7200,
"AllowedScopes": [
"openid",
"profile",
"email",
"offline_access"
]
}
Client side
export const IDENTITY_CONFIG = {
authority: process.env.REACT_APP_AUTH_URI,
client_id: process.env.REACT_APP_IDENTITY_CLIENT_ID,
redirect_uri: process.env.REACT_APP_BASE_URI + process.env.REACT_APP_REDIRECT_PATH,
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true,
silent_redirect_uri: process.env.REACT_APP_BASE_URI + process.env.REACT_APP_SILENT_REDIRECT_PATH,
post_logout_redirect_uri: process.env.REACT_APP_BASE_URI + process.env.REACT_APP_LOGOFF_REDIRECT_PATH,
response_type: 'code',
scope: process.env.REACT_APP_SCOPE
};
"base": {
"REACT_APP_TESTENV": "1",
"REACT_APP_IDENTITY_CLIENT_ID": "reactclient",
"REACT_APP_REDIRECT_PATH": "signin-oidc",
"REACT_APP_SILENT_REDIRECT_PATH": "silentrenew",
"REACT_APP_LOGOFF_REDIRECT_PATH": "logout/callback",
"REACT_APP_SCOPE": "openid profile email",
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
},
"development": {
"REACT_APP_TESTENV": "development",
"REACT_APP_AUTH_URI": "https://localhost:44318",
"REACT_APP_AUTH_ISSUER": "https://localhost:44318",
"REACT_APP_BASE_URI": "https://localhost:44309/",
"REACT_APP_SERVICE_MEMBER_BASE_URI": "https://localhost:44320/"
},
Identity server side code. similar to https://github.com/IdentityServer/IdentityServer4.Demo/blob/master/src/IdentityServer4Demo/Quickstart/Account/AccountController.cs
public async Task<IActionResult> Login(LoginInputModel model)
{
var returnUrl = model.ReturnUrl;
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
//
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberLogin, lockoutOnFailure: false);
if (result.Succeeded)
{
Logit("User logged in.");
return RedirectToLocal(returnUrl);
}
else if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(VerifyCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberLogin });
}
else if (result.IsLockedOut)
{
Logit("User account locked out.");
return View("Lockout");
}
else
{
//check if user exists in BIZZ db
ModelState.AddModelError(string.Empty, _sharedLocalizer["INVALID_LOGIN_ATTEMPT"]);
return View(await BuildLoginViewModelAsync(model));
}
}
// If we got this far, something failed, redisplay form
return View(await BuildLoginViewModelAsync(model));
}
Can anyone explain how I can redirect to specific page instead of going to home page each time after login. I would want to solve this at identity server instead at client side.
You have to use history in reactjs to get previous path and need to save in sessionStorage.
May be this will help you :
const SAVED_URI = 'APP_PLU';
const FORBIDDEN_URIS = ['/login-response', '/'];
const DEFAULT_URI = '/';
function setPostLoginUri() {
// using just the pathname for demo, should be more detailed in production to
// include query params, hash bangs, etc
const currentPath = window.location.pathname;
const savedURI = sessionStorage.getItem(SAVED_URI);
if (FORBIDDEN_URIS.includes(currentPath) || savedURI) {
return;
}
sessionStorage.setItem(SAVED_URI, currentPath);
}
function getPostLoginUri(retain) {
const savedURI = sessionStorage.getItem(SAVED_URI);
if (!retain) {
sessionStorage.removeItem(SAVED_URI);
}
return savedURI || DEFAULT_URI;
}
export default {
get: getPostLoginUri,
set: setPostLoginUri
};
And set in the app.js
and then in your login response page add this code ,
function LoginResponse({ history, setUser }) {
const [error, setError] = useState(null);
useEffect(() => {
// the login redirect has been completed and we call the
// signinRedirectCallback to fetch the user data
userManager.signinRedirectCallback().then(user => {
// received the user data so we set it in the app state and push the
// router to the secure or bookmarked route
setUser(user);
history.push(postLoginUri.get());
}, ({ message }) => {
// userManager throws if someone tries to access the route directly or if
// they refresh on a failed request so we just send them to the app root
if (message && redirectErrors.includes(message)) {
history.push('/');
return;
}
// for all other errors just display the message in production it would be
// a good idea to initiate a sign out after a countdown
setError(message);
});
}, []);
return error;
}
export default LoginResponse;

react-fine-uploader to authenticate in the backend with redux-token-auth

In my stack I am using redux-token-auth to authenticate users with my rails backend (devise_token_auth). In my app I need to allow authenticated users to upload images, for this I'm using react-fine-uploader.
My problem is that I'm not seeing a way to have ract-fine-uploader to POST the images in an authenticated way. and in general how to use redux-token-auth to upload data to my backend with authentication.
I found that redux-token-auth stores authentication tokens in the localStorage, so I'm kinda able to retrieve it and authenticate my requests. Though I don't like accessing such data directly with a localStorage.get("access-token") (It's written by the package, it just seems fair to use the package to handle it).
Also with react-fine-uploader the response object doesn't contain the headers from the server response, so I'm not sure on how to get the new tokens to store them.
Here's the code I got so far:
my ImagesUploader:
import React from "react";
import PropTypes from "prop-types";
import FineUploaderTraditional from "fine-uploader-wrappers";
import Gallery from "react-fine-uploader";
import { backend } from "../../libs/itemTools";
import "react-fine-uploader/gallery/gallery.css";
const ImagesUploader = props => {
const uploader = new FineUploaderTraditional({
options: {
multiple: false,
validation: {
itemLimit: 1
},
request: {
endpoint: backend.createImage,
customHeaders: {
"access-token": localStorage.getItem("access-token"),
"token-type": localStorage.getItem("token-type"),
client: localStorage.getItem("client"),
uid: localStorage.getItem("uid")
}
},
session: {
endpoint: backend.loadImages(props.itemId)
},
deleteFile: {
enabled: true,
endpoint: backend.deleteImage(props.itemId)
},
cors: {
expected: true
},
callbacks: {
onComplete: (id, name, response, xhr) => {
if (response.success) {
response.image.id;
//TODO save new access-token
// ####### THIS DOESN'T work, #########
//fine-uploader doesn't include headers in the response object.
localStorage.setItem("access-token", response.headers["access-token"]);
localStorage.setItem("token-type", response.headers("token-type"));
localStorage.setItem("client", response.headers(client));
localStorage.setItem("uid", response.headers(uid));
} else {
// [...]
}
},
onSessionRequestComplete: (...params) => {
console.log(
"onSessionRequestComplete: " + JSON.stringify(params, 0, 2)
);
}
}
}
});
return (
<div id="upload-area">
<Gallery uploader={uploader} />
</div>
);
};
ImagesUploader.propTypes = {
userId: PropTypes.number.isRequired,
itemId: PropTypes.number.isRequired
};
export default ImagesUploader;
It seems strange to me that redux-token-auth packages doesn't account for authenticated backend calls, and that fine-uploader doesn't give access to the response headers..
Is there maybe something I'm missing?
From taking a look at redux-token-auth, it expects to handle all auth calls and doesn't give you an escape hatch in the code - so yanking the localstorage seems like a prudent thing to do there. You can see in the code that it sets it for every request: https://github.com/kylecorbelli/redux-token-auth/blob/8c5a8fe573918d406a733ca1b21c0b4349f137ab/src/actions.ts#L160
As for fine-uploader it looks like you can grab the rawheaders by using xhr.response
https://github.com/FineUploader/fine-uploader/blob/master/client/js/traditional/traditional.xhr.upload.handler.js#L59
The response variable that you get back has been JSON parsed via the qq variable you pass in: https://github.com/FineUploader/fine-uploader/blob/master/client/js/traditional/traditional.xhr.upload.handler.js#L109

Resources