Azure ad authentication SPA token not able to authenticate by my API - reactjs

I have API and SPA at same azure. I already set the Expose an API and gave permission on my SPA.
but when I login on my SPA the return token that I pass to my API is not authorized.
any thing else I need to do into my SPA?
I use React js and MSAL to login.

You may miss the scope. The scope is format as api://{client_id}/.default.
There is a sample using the on-behalf-of flow: https://github.com/Azure-Samples/ms-identity-javascript-react-spa-dotnetcore-webapi-obo
In ProfileSPA/src/utils/authConfig.js:
export const apiConfig = {
resourceUri: "https://localhost:44351/api/profile",
resourceScopes: ["Enter the API scopes as declared in the app registration 'Expose an Api' blade in the form of 'api://{client_id}/.default'"]
}
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow#use-the-access-token-to-access-the-secured-resource

Related

Client - API authentication flow with Microsoft Azure AD

I'm building a react frontend application with a spring backend that is secured with azure ad.
I can't get the authentication flow to work.
In azure ad, I have registered 2 applictions:
API: Default configurations and under "Expose an API" I have added a scope with api://xxxx-api/Access.Api and also added the client application. Under "App Roles" I have added the roles "User" and "Admin". I have assignes both roles to myself.
Client: Registered as SPA with redirect to http://localhost:3000 where the react app is running. Did not check the two boxes for the token to enable PKCE. Under "API permissions" I added the "Access.Api" scope from the api app and granted admin consent.
In the react app I'm using #azure/msal-browser and #azure/msal-react.
My authConfig looks like this:
Then I'm just using useMsalAuthentication(InteractionType.Popup); to sign the user in.
All this works as expected and I'm getting a token back. If I parse this token in jwt.io,
I get "iss": "https://sts.windows.net/42xxxxx-xxxxx-xxxxxx-xxxxx/",
"scp": "openid profile User.Read email", "ver": "1.0",.
However, I do not see the scopes or roles for my API app.
I'm then using an Axios request interceptor to provide the bearer token on every API request:
const { instance, accounts } = useMsal();
const account = useAccount(accounts[0]);
axios.interceptors.request.use(async (config) => {
if (!account) {
throw Error('No active account! Verify a user has been signed in.');
}
const response = await instance.acquireTokenSilent({
...loginRequest,
account,
});
config.headers.Authorization = `Bearer ${response.accessToken}`;
return config;
});
The token is successfully added to the header of each request.
My spring application however fails to validate this token.
My spring config:
I could implement the token validation myself if that is an issue here, but how do I fix, that the bearer token does not contain the roles that I need to check if the user has access to specific resources on the api?
I figured it out.
Basically the scopes openid, email and profile should only be used when requesting an ID token. The ID token contains all roles exposed in the client app.
If these scopes are used when requesting an access token, the token will contain no roles or scopes at all. Only use the scope from the api app that is exposed in the client app when requesting an access token, and the roles will show up in the access token.

EasyAuth with a SPA and AzureFunction on different hosts

I'm trying to use EasyAuth (aad) with a SPA, which is on "localhost:8080" at the moment, and an Azure Function which is hosted in Azure ({function-app}.azurewebsites.net. The intent is for the SPA to call a secured endpoint on the Azure Function. So, I have the Azure Function Registered as an application in AD, and the authentication redirect in the SPA to the Azure Function EasyAuth endpoint appears to be working, but the redirect back to the localhost SPA via the post_login_redirect_url is not.
I added http://localhost:8080 to the AAD registered application as an allowed redirect URI. However, if I fully qualify the URL I am redirected back to {function-host}/.auth/login/done. Is there an expectation that the SPA runs under the same hostname as the azure function, or is there a way to configure the setup to allow any URL for the SPA host?
Behavior
In terms of HTTP data during behavior, once login succeeds .auth/login/aad/callback is loaded with the following prior to redirecting to the default done page and stopping.
Response Header
Location = {function-host}/.auth/login/done
Form Data:
state = http://localhost:8080
code = auth code
id_token = auth token
How I called it from the SPA
function processAuthCheck(xmlhttp) {
if (xmlhttp.status == 401) {
url = "https://{function-app}.azurewebsites.net/.auth/login/aad?"
+ "post_login_redirect_url=" + encodeURI("http://localhost:8080");
window.location = url;
} else if (xmlhttp.status != 200) {
alert("There is an error with this service!");
return;
}
var result = JSON.parse(xmlhttp.responseText);
console.log(JSON.stringify(result));
return;
};
Regarding the issue, please refer to the following steps
Register Azure AD application to protect azure function with easy auth
Register client-side application
a. Register single-page application
b. In the Implicit grant and hybrid flows section, select ID tokens and Access tokens.
c. Configure API permissions
Enable CORS in Azure function
Code
a. Integrate Azure AD auth in your spa application with Implicit grant flow. After doing that, when users access your application, they need to enter their AD account to get access token
b. Client exchanges this accessToken for an 'App Service Token'. It does this by making a POST to https://{app}.azurewebsites.net/.auth/login/aad with the content { "access_token" : "{token from Azure AD}" }. This will return back an authenticationToken
c. Use that authenticationToken in a header named x-zumo-auth. Make all requests to your function app using that header.
For more details, please refer to here and here. Regarding how to implement Azure AD in spa, please refer to here.

How to access a web api secured with Azure AD B2C using react js

I am having a .net core web api which is secured with Azure AD B2C and I am trying to access the api using react js msal library.
new Msal.UserAgentApplication(config.applicationId,
authority,
authCallback,
{ logger: logger,
cacheLocation: config.cacheLocation,
postLogoutRedirectUri: config.postLogoutRedirectUri,
redirectUri: config.redirectUri }
);
How to call a web api by passing the JWT token by using react js
It looks like you are using MSAL js v0.2.3 or v0.2.4, the new MSAL v1.0.0 release takes a configuration object in the constructor for the UserAgentApplication. Make sure to refer to the documentation for correct usage for your version:
https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki
Regardless - you'll need to initiate a login after initialization by calling loginPopup or loginRedirect on the MSAL app. After successful credentials are entered and you return to your web app, you can call MSAL's getUser() ( or getAccount() if using v1.0.0 )
After that, you'll need to get an access token by calling acquireTokenSilent(scopes), where the scopes array is defined by your B2C application.
( In v1.0.0 you'd pass a parameter object like this: { scopes: [scopes] } )
Once you have an access token - you'll need to pass it as the Authorization header on your REST request, and then validate it in your WebAPI by calling back to B2C before processing the request.
This is an example of the validation process:
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapi-manual-jwt-validation/

React protect admin panel using JsonWebToken

I got a single page app written with React and ReactRouter and the frontend seems to be easy going.
But I have no idea how to design a backend which is only accessable by admins. On the server-side I use a NodeJS / Express RESTful API which uses JWT (JsonWebToken) for authentication.
Do you have any ideas?
You can use Express Middleware to check and validate JWT. If the JWT is valid then proceed with the API otherwise redirect to login. There are lots of articles available on ExpressJs site about middleware.
One great option is express-jwt
You import it, make a middleware, and place it before any protected route. If the token is valid, req.user will be set with the JSON object decoded to be used by later middleware for authorization and access control.
const jwt = require("express-jwt");
const auth = jwt({
secret: jwt_secret
});
router.get("/secret/:uid", auth, profileCtrl.secret);

API on subdomain and oauth

I have an api on a subdomain : api.exemple.com written with symfony2 and my main application on exemple.com (SPA - AngularJs).
I would like to allow user to link their facebook account with their local account. I don't know how to proceed in order to authenticate through my app and use third party oauth provider.
Do you have any clue ?
Thank you
On the angular side, start by opening a new window and send your oauth handler a get request:
self.oauthConnect = function(provider)
{
var url = apiPrefix + '/oauth/tokens/'. provider;
oauthWindow = $window.open(url,'_blank', 'height=600, width=600, top=100, left=300, modal=yes');
oauthWindow.focus();
};
Your PHP api site then redirects to the oauth provider site (i.e. facebook). We use a new client window so our SPA keeps running in spite of the redirect. The provider then presents their login screen and redirects with the oauth token information.
Your PHP api site does what it needs to and generates the actual authorization token (hint: use a json web token). The site then returns an html page back to your angular app.
<body>
<script>
window.opener.oauthCallback('<?php echo $oauthToken; ?>');
</script>
</body>
Your angular controller (that opened the window) will then be called with the oauth token.
$window.oauthCallback = function(oauthToken)
{
oauthWindow.close();
oauthWindow = null;
authManager.oauthToken = oauthToken;
self.oauthSubmit();
};
Easy right? Well not really but it works. In my case I turn right around and:
POST /auth/tokens/oauthToken
to get the real application token. That way my oauth service can be used for multiple applications.

Resources