Integrate Azure AD with AngularJS and call CORS web api - angularjs

After going through the article https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v1-angularjs-spa, we have created a web application named ToDoSpa and web api named ToGoApi registered in Azure Active Directory and are able to authenticate but the problem lies in consuming the web api including the endpoints as
AADSTS65001: The user or administrator has not consented to use the application with ID '2528e8f3' named 'ToDoSpa '. Send an interactive authorization request for this user and resource.
Trace ID: df70a02e-6a53-4899-8319-0ba440540500
Correlation ID: 699515a6-dccb-421e-92ae-e9b5a700ad1b
Timestamp: |interaction_required".
Client Id:
ToDoSpa->2528e8f3
ToGoApi->815933a4
In ToDoSpa,we have defined the scopes for the application ToDoSpa as "User.Read and Directory.Read.All" and authorized the client application using the client ID of web api(815933a4) in Expose API. In App permission, we have included ToDoSpa and have grant consent the application.
app.js
var endpoints = {
"https://graph.microsoft.com": "https://graph.microsoft.com",
"https://localhost:44392/api/weather": "https://firstupconsultants.onmicrosoft.com/ToGoApi"<!--localhost:App Id Uri of Server-->
};
adalProvider.init({
instance: 'https://login.microsoftonline.com/',
tenant: '<tenant-id>',
clientId: '<client-id of server>',
endpoints: endpoints,
extraQueryParameter: 'prompt=admin_consent'
}, $httpProvider);
}]);
//Get
weather1.getWeather = function () {
return $http.get("https://localhost:44392/api/weather").then(succeessCallback, failedCallback);
function succeessCallback(weather) {
//$scope.weather = weather.data;
weather1.items = weather.data;
}
function failedCallback(error) {
console.log("An error has occurred:", error);
}
}
web.config
<add key="ida:Tenant" value="<tenant-id>"/>
<add key="ida:Audience" value="https://firstupconsultants.onmicrosoft.com/ToGoApi"/>
<!--localhost:App Id Uri of Server-->

Typically, when you build an application that uses application permissions, the app requires a page or view on which the admin approves the app's permissions. This page can be part of the app's sign-in flow, part of the app's settings, or it can be a dedicated "connect" flow.
When you're ready to request permissions from the organization's admin, you can redirect the user to the Microsoft identity platform admin consent endpoint.
Here is sample URL for the same:
GET https://login.microsoftonline.com/{tenant}/adminconsent?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&state=12345
&redirect_uri=http://localhost/myapp/permissions
When you want to enable the users on other tenant can use the application, the application required to give the consent first. To do that you can make a HTTP request to grant the admin consent easily by using the prompt parameter.
You can read about this in detail in below doc:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#request-the-permissions-from-a-directory-admin
Additional reference:
https://blog.mastykarz.nl/implementing-admin-consent-multitenant-office-365-applications-implicit-oauth-flow/
Hope it helps.

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.

Blazor WASM with Azure AD SSO

I have a Blazor WASM client and a Web API with working Azure AD authentication and authorization but the users always have to push the button to log in. I want to use SSO for make them easy this process. I tried to find on Internet how I can put this feature in the application but no success. Can someone to show the right direction, please?
I do not insert source code because those who are experienced in this will know what it is about. Thx
• Yes, you can configure SSO in Blazor WASM app very easily by following the below said procedure as shown. Also, you need to determine the authentication method for the Blazor WASM app, i.e., SAML, OAuth 2.0, OpenID as such. Therefore, I am considering SAML as the authentication mechanism in here.
To facilitate the SAML SSO authentication through Azure AD, you will have to install packages related to it in your .NET Core product from its official website. Here, we are using ‘ComponentSpace.SAML.2.0’ package using the NuGet Manager. Once the installation is complete, we need to inject the service of ‘ComponentSpace’ in our project by adding service and cookies in the ‘Program.cs’ file whose code looks like this: -
builder.Services.Configure<CookiePolicyOptions>(options =>
{
// SameSiteMode.None is required to support SAML SSO.
options.MinimumSameSitePolicy = SameSiteMode.None;
});
builder.Services.ConfigureApplicationCookie(options =>
{
// Use a unique identity cookie name rather than sharing the cookie across applications in the domain.
options.Cookie.Name = “StudentPortal.Identity”;
// SameSiteMode.None is required to support SAML logout.
options.Cookie.SameSite = SameSiteMode.None;
});
// Add SAML SSO services.
builder.Services.AddSaml(builder.Configuration.GetSection(“SAML”));
Once done, we can modify the ‘appsettings.json’ file to add to the ‘ComponentSpace’ settings. There are many parts which we can add in the ‘appsettings.json’ file,i.e., ‘schema’, ‘LocalServiceProviderConfiguration’, ‘PartnerIdentityProviderConfigurations’, ‘SingleSignOnServiceUrl’, ‘SingleLogoutServiceUrl’ and ‘ArtifactResolutionServiceUrl’ refers to the IDP server side’s service URL wherein it should be your Azure Cloud’s URL and these URLs are where our applications send sign-on and logout requests which also includes the ‘PartnerName’, i.e., IDP’s name and URL.
To do so, you will have to include the below in your ‘appsettings.json’ file placed under ‘wwwroot’ folder: -
{
"oidc": {
"Authority": "< insert the SSO provider URL here >",
"ClientId": "< unique client id as specified in the SSO provider >",
"ResponseType": "code",
"DefaultScopes": [
"openid",
"profile"
],
"PostLogoutRedirectUri": "authentication/logout-callback",
"RedirectUri": "authentication/login-callback"
}
}
Thus, once done, we will add a new file to the same folder by the name of ‘LoginDisplay.razor’ which is displayed as follows: -
#using Microsoft.AspNetCore.Components.Authorization
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
#inject NavigationManager Navigation
#inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
<button class="nav-link btn btn-link" #onclick="BeginSignOut">Log out</button>
</Authorized>
<NotAuthorized>
Register
Log in
</NotAuthorized>
</AuthorizeView>
#code{
private async Task BeginSignOut(MouseEventArgs args)
{
await SignOutManager.SetSignOutState();
Navigation.NavigateTo("authentication/logout");
}
}
Thus, as all the configurations required are done as given above, the program will call ‘SAML/InitiateSingleSignOn’ function and send an SSO sign-in request to IDP, and now our program automatically run into the ‘SAML/AssertionConsumerService’ function and start to wait for IDP's reply, after receiving the response from the IDP. Please find the below snapshots for your reference while following the above steps: -
Certificate import: -
Adding ‘SAML Service Provider’ as a SAMLController as said: -
Adding ‘ComponentSpace.SAML.2.0’ package as below: -
For more detailed information, kindly refer to the below links: -
https://kevinzheng1989.medium.com/build-the-azure-sso-login-page-in-blazor-server-application-with-saml-b0959a50c0a6
https://scientificprogrammer.net/2022/08/12/single-sign-on-user-authentication-on-blazor-webassembly-signalr-client/

InteractionRequiredAuthError: AADSTS65001: The user or administrator has not consented to use the application with ID

Trying to create a simple SPA and call a Rest API in Azure, and I am getting InteractionRequiredAuthError: AADSTS65001: The user or administrator has not consented to use the application with ID 'xxx' named 'MySpaApp'. Send an interactive authorization request for this user and resource.
Did the following:
Registered the REST Api application
Added permission for MyRestApi.Tasks.Get, its status is Granted for my users
Added a scope for Tasks.Get
Added a client application using the SPA application's Client Id
Registered the SPA application
URI is http://localhost
Implicit grant and hybrid flows:
Access tokens checked
ID tokens checked
Supported account types: any organizational directory
API Permissions, added MyRestApi.Tasks.Get
In Enterprise Applications, MySpaApp, clicked Grant Admin Consent for my users
Went back to MySpaApp, and verified that Tasks.Get has been granted
From MySpaApp, if I call msal.acquireTokenSilent with "Tasks.Get" for scope, I get:
The user or administrator has not consented to use the application with ID 'xxx' named 'MySpApp'. Send an interactive authorization request for this user and resource.
If I call call msal.acquireTokenSilent with "User.Read" for scope, I get back a token.
Any further ideas on troubleshooting?
Try my method:
Register an SPA in Azure and check id token and access token.
Then register a REST Api application and expose the api, and then add the client id of the spa application to the REST Api application.
Next, go to the spa application.
Under 'API permissions' click on 'Add permission', then click on the
'My APIs' tab.
Find your api application and select scope.
Click 'Add permissions'.
Grant admin consent.
Then use the implicit flow in the browser to get the token.
https://login.microsoftonline.com/{tenant id}/oauth2/v2.0/authorize?
client_id={client_id}
&response_type=id_token token
&redirect_uri={redirect_uri}
&scope=openid api://{api app client id}/{scope name}
&response_mode=fragment
&state=12345
&nonce=678910
Parse the 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.

Secure .Net Core 3 Web API with AAD Token

Due to some technical constraints, we are doing Username/Password AAD authentication when user login.
Users will input their username and password into our custom login page and our application calls IPublicClientApplication.AcquireTokenByUsernamePassword.
I'm planning to use the returned token to call another Web API application(also connecting to the same AAD). In the Web API application, I did the following:
Added the following code in startup services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
include the following settings in my appsettings.json file
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "<Application ID>",
"TenantId": "<Tenant ID>"
}
Secure my web api using [Authorize]
I then use Postman to construct a call to the Web API based on the returned token. I included Authorization: Bearer <JWT Token>. The Web API returns
Bearer error="invalid_token", error_description="The signature is invalid"
My questions are
Can Web API application validate the username/password acquired token?
If the token can be validated in Web API application, how can I do it since I'm getting the above error?
I test in my site and it work well, you could refer to the following steps:
1.Register Webapi app in azure ad.
2.Click Expose an API and Add a scope e.g. webread.
3.Click Manifest, change accessTokenAcceptedVersion to 2.0.
4.In visual studio webapi ConfigureServices:
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme,
options =>
{
options.Authority += "/v2.0";
options.TokenValidationParameters.ValidAudiences = new[]
{
options.Audience,
$"api://{options.Audience}"
};
});
5.Register client app in azure ad.
6.Click Authentication, set Default client type as Yes.
7.Click Api Permission>Add a permission, select My APIs and choose the webapi your registered before.
8.In visual studio client app, set scope with webread:
string[] scopes = new string[] { "api://1890e822-xxxxxxxxxxxxxxxx/webread" };
Hope it helps you.
From the document you provided you are using MSAL to get access token using Resource Owner Flow in Azure AD V2.0 endpoint .
From document , when validating access token which issued from Azure AD V2.0 , you should add /v2.0 to Authority :
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
{
// This is a Microsoft identity platform web API.
options.Authority += "/v2.0";
// The web API accepts as audiences both the Client ID (options.Audience) and api://{ClientID}.
options.TokenValidationParameters.ValidAudiences = new []
{
options.Audience,
$"api://{options.Audience}"
};
});

Resources