Setting jwt audience in Azure Mobile Apps backend - node.js

I am playing with an Azure Mobile Apps backend (nodeJS), as discussed here. I have been using the default web setup configuration to develop my mobile app, but now I want to customise the cloud backend functionality, so I have created a local backend with the Azure-Mobile-Apps SDK.
I logged in with my mobile app (using the authorization aspect of the Azure client SDK) and then captured the AuthToken, using a live managed backend setup.
When I then come to try and authorise a request, I get the following issue:
{ "name": "JsonWebTokenError", "message": "jwt audience invalid. expected: urn:microsoft:windows-azure:zumo" }
Following on from: Locally Testing Azure Mobile Auth - invalid jwt signature
How can I set the jwt audience?

To set the audience and issuer, use the auth:{} object in your azureMobile.js. You can decode the JWT at jwt.io to see what the audience and issuer are, then do:
auth: {
audience: '<your audience>',
issuer: '<your issuer>'
};
Some good references:
My blog post on Custom Auth
The main configuration reference (which azureMobile.js exports)

Related

Getting Error AADB2C99067 when trying to request access token from Azure B2C

I have an Azure AD B2C tenant setup with an Angular app on the front-end using Authorization Code Flow with PKCE and a back-end api. Everything is working fine. I now have a need to allow the user to access certain pages on the front-end anonymously. I would prefer to still protect the apis these pages will call using the same access token.
I have followed the article here to set up Client Credentials flow. I am able to get an access token successfully using Postman and use it to call my back-end apis fine. However, when I try to do the same from the Angular app, I get the following error:
{"error":"invalid_request","error_description":"AADB2C99067: Public Client XXXXX-XXXXXX is not supported for Client Credentials Grant Flow\r\nCorrelation ID: 2b3346ef-1828-4900-b890-06cdb8e0bb52\r\nTimestamp: 2022-07-28 04:12:21Z\r\n"}
Below is the code snippet I am using in Angular to retrieve the access token.
const urlencoded = new URLSearchParams();
urlencoded.set('grant_type', 'client_credentials');
urlencoded.set('client_id', '<clientid>');
urlencoded.set('client_secret', '<clientsecret>');
urlencoded.set('scope', '<scope>');
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }),
};
const url = 'https://<b2ctenant>.b2clogin.com/<b2ctenant>.onmicrosoft.com/<customPolicy>/oauth2/v2.0/token';
return this.httpClient.post(url, urlencoded, httpOptions);
Any ideas what could be missing?
Thanks!
Though azureadb2c supports client_credential flow.One may not use them with SPA apps.
This scenario is not supported by MSAL.js. Client credential flow/ grant type will not work in SPAs(Angular) because browsers cannot securely keep client secrets.
As they may end up in the browser, visible to everyone and to attackers that load them.
Note:As the application's own credentials itself are being used, they must be kept safe - never publish that credential in your source
code
If you are using it for web app , please make sure to select the platform as web or change the reply url type to be web.
"replyUrlsWithType": [
{
"url": "https......",
"type": "Web"
},
]
Please refer :
Configure authentication in a sample Angular SPA by using Azure
Active Directory B2C | Microsoft Docs
OAuth 2.0 client credentials flow on the Microsoft identity platform- Microsoft Entra | Microsoft Docs

"authentication failed due to: jwt audience is invalid" with Azure AD

First I'm describing how I setup my applications then I will describe how I'm using the APIs.
Setup
In my Azure Active Directory, I have two applications registered: UI and Backend
UI has the client ID clientId1 and backend has client ID clientId2 (it's a GUID, but for simplicity)
Both are under the same tenant tentant1 (single tenant)
Backend (Web API)
Backend has an exposed API with scope "api://clientId2/access_as_user" and authorized client "clientId1" with the scope just mentioned selected
I'm using passport and passport-azure-ad (I pretty much copied https://github.com/Azure-Samples/active-directory-javascript-nodejs-webapi-v2).
My config:
const config = {
identityMetadata: "https://login.microsoftonline.com/tenant1/v2.0/.well-known/openid-configuration",
clientID: "clientId2",
validateIssuer: false,
loggingLevel: 'info',
passReqToCallback: false,
loggingNoPII: false
};
I get this message when starting the server:
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":16052,"level":40,"msg":"Production environments should always validate the issuer.","time":"2020-04-11T13:25:44.283Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":16052,"level":30,"msg":"In BearerStrategy constructor: created strategy with options {\"identityMetadata\":\"https://login.microsoftonline.com/tenant1/v2.0/.well-known/openid-configuration\",\"clientID\":\"clientId2\",\"validateIssuer\":false,\"loggingLevel\":\"info\",\"passReqToCallback\":false,\"loggingNoPII\":false,\"clockSkew\":300,\"allowMultiAudiencesInToken\":false,\"audience\":[\"clientId2\",\"spn:clientId2\"]\"isB2C\":false,\"_isCommonEndpoint\":false}","time":"2020-04-11T13:25:44.285Z","v":0}
Listening on port 5000
UI (Angular SPA)
UI has permissions was granted automatically permission to access Microsoft Graph (profile, user.read, user.read.all -- last one I think I granted). The permissions are in "API permissions"
I went ahead and also granted access to the Backend access_as_user
For the UI code I'm using the MSAL library and again I pretty much copied the repo (https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-angular)
In the protectedResourceMap field I added the following
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['http://localhost:5000', ['api://clientId2/access_as_user']],
I am able to log in and read my user profile, but when trying to access http://localhost:5000/hello (protected), I'm getting the error the title of this question
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":20720,"level":30,"msg":"authentication failed due to: jwt audience is invalid","time":"2020-04-11T13:38:08.700Z","v":0}
--
I can see the Bearer Token coming (in the UI and backend), the server decodes the token (I can see all my profile info in the server logs), but it's saying the JWT is invalid?!
I'm not defining an audience, yet I can see in the token when it gets decoded the audience with aud: 'api://clientId2'.
I can also see when the backend starts it shows the audience as [clientId2, sps:clientId2] by default (step4 on the backend). When I define in the config audience: 'api://clientId2', I get a 403 with the message:
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":12644,"level":30,"msg":"In Strategy.prototype.jwtVerify: We did not pass Req back to Callback","time":"2020-04-11T16:19:30.398Z","v":0}
Any help would be appreciated. Thank you.
Turns out their code in the repository is not using proper configuration to verify the scope access...
https://github.com/Azure-Samples/active-directory-javascript-nodejs-webapi-v2/blob/master/index.js#L41
if (req.authInfo['scp'].split(" ").indexOf("demo.read") >= 0) {
I needed to change the scope from "demo.read" to "access_as_user".
In my case it was just that the clock of my VM where the application was running on was 15mins behind. So the time of the token was created was in the future...

Accessing AD secured Azure Function via AJAX

I have an Azure Function setup with a Web Trigger endpoint that I want to use as my backend for a React app. Without authentication setup, it works fine. When I setup App Service Authentication using AD, it works fine when I access directly via the browser (after authentication), but when I try to access from JS providing the Bearer token I get a 401.
const response = await axios.get(`${window.apiUrl}api/jobs`, {
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + token.accessToken,
},
});
The client app is running on Azure and is registered as an Azure AD app. I am able to authenticate, query AD, and use MS Graph API successfully.
I am using the built-in Azure App Services AD authentication. I have the Client ID set as the same client ID as the previously mentioned Azure AD app, as well as the same Issuer Url.
Attempt to get session token:
const accessToken = await authProvider.getAccessToken();
const idToken = await authProvider.getIdToken();
const login = await axios.post(
'https://<appname>.azurewebsites.net/.auth/login/aad',
{ access_token: accessToken.accessToken },
{
headers: {
'Content-Type': 'application/json',
},
},
);
More Info
My aud claim is 00000003-0000-0000-c000-000000000000. In Azure Portal, my Azure Function is configured to use the same Azure AD App as my SPA. I am using MSAL.js for authentication in my SPA. I am requesting the User.Read and Directory.Read.All scopes.
Microsoft has published a how-to article entitled Advanced usage of authentication and authorization in Azure App Service. In the section on validating tokens from providers, it says:
In a client-directed sign-in, the application signs in the user to the
provider manually and then submits the authentication token to App
Service for validation (see Authentication flow). This validation
itself doesn't actually grant you access to the desired app resources,
but a successful validation will give you a session token that you can
use to access app resources.
So you need to get the session token to access app resources.
Request:
POST https://<appname>.azurewebsites.net/.auth/login/aad HTTP/1.1
Content-Type: application/json
{"id_token":"<token>","access_token":"<token>"}
Response:
{
"authenticationToken": "...",
"user": {
"userId": "sid:..."
}
}
Once you have this session token(authenticationToken), you can access protected app resources by adding the X-ZUMO-AUTH header to your HTTP requests
GET https://<appname>.azurewebsites.net/api/products/1
X-ZUMO-AUTH: <authenticationToken_value>
You cannot request a token for Microsoft Graph and use it to call your own API. The Audience "00000003-0000-0000-c000-000000000000" means "intended for Microsoft Graph".
In MSAL, when you request the token, you need to adjust the scopes. Delete User.Read, delete Directory.Read.All and add the "Application ID URI" with a /.default at the end of it. You can find the Application ID URI in the "Expose an API" blade of your application registration on portal.azure.com. Example: https://SaeedApp/.default
If you need to do both, you can only request an access token for one resource at a time. However, you can request as many scopes as you need for one resource (User.Read and Directory.Read.All are both scopes for the same resource).
So you'll need to make two sets of requests:
1) to get an access token with all the scopes you need for Microsoft Graph
2) to get an access token with all of the scopes you need for your API
The reason behind why: If I could take an access token that's intended for your API and call Microsoft Graph with it, then that would open up "replay" attacks where one Resource API is hacked and the hacker that controls one resource can now reply access tokens it receives from clients against all the other Resource APIs.

Azure AD Token based Authentication for WebAPI

We have developed Web API in .net Core 2.1 without authentication.
But now we are trying to add the Azure AD token based authentication.
we have registered app in azure AD and we did necessary changes in startup.cs file. and added authorize tag
When we test the API in postman we generated token we are getting Microsoft login page in Html format as result.
when we crosscheck the API in browser, its asking domain user name and password by providing the user name password we are getting the result.
Its seems some configuration or setting missing in Azure AD setup or code.
Can anyone help on this. other wise anyone share the steps for token based authentication implementation for API.
If you already have the api , you should firstly register an app in Azure Portal .
In your api application , you can follow the below steps :
Install the package Microsoft.AspNetCore.Authentication.AzureAD.UI
Register the Azure AD Bearer authentication service in ConfigureServices function :
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
In appsettings.json , set the correct api configuration from Azure Portal :
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "YourDomain.onmicrosoft.com",
"TenantId": "cb1c3f2e-a2dd-4fde-bf8f-f75ab18b21ac",
"ClientId": "83bf146d-4948-4596-a4b3-b7b2e68ac3e0"
},
Tenant ID ,domain name and API's ClientId could be find in Azure Portal .Then you can add Authorize attribute on protected controllers/actions . If you have multiple authentication schema , you can authorize with a specific scheme .
You client app will uses the OpenID Connect middleware and the ADAL/MSAL to obtain a JWT bearer token for the signed-in user using the OAuth 2.0 protocol. The bearer token is passed to the web API, which validates the token and authorizes the user using the JWT bearer authentication middleware.

Calling an Azure AD secured Web API from Angular Frontend

I am currently developing an Angular Frontend, which uses MSAL to authenticate users. This Frontend should call a Web-API (also hosted in Azure), which is secured by Azure Active Directory.
While I easily managed to work with Angular and MSAL, getting a Token and successfully calling Graph/me as test, I cannot get the API call to work, I'm always receiving 401's.
I'm using the following setup:
Angular frontend with MSAL
I created an Application in AAD, gave it User.Read permissions for MS Graph, copied the ID into the MSAL code and using the MSAL Interceptor calling Graph API was pretty easy following the documentation.
Web-API
I created a web-api with in .NET core, simply returning some demo data in the GET. I published the API to an azure Web Application (https://myappurl.azurewebsites.net/api/test, calling it from Angular or Postman was no Problem
Auth
Using the Azure Portal, in the App Web settings, I activated web service authentication with Azure Active Directory. As the required application, I put the same one I used in step 1 for the Frontend.
At this point I was not able to call my API any more, always receiving 401's.
I parsed the JWT Token out of the Angular code and tried postman calling with Authorization: Bearer eyJ0xxxxx headers, still 401.
I thought, that by "logging into" my frontend I should be able to use the token to identify myself for the API call aswell, since it uses the same app-id, but somehow I think I got it mixed up. I looked at a lot of documentation, but it's mostly outdated since the App registration changes in Azure Portal.
export const protectedResourceMap:[string, string[]][]=[['https://graph.microsoft.com/v1.0/me', ['user.read']] ];
MsalModule.forRoot({
clientID: "my-client-id",
redirectUri: "http://localhost:4200/profile",
postLogoutRedirectUri: "http://localhost:4200/bye",
authority: "https://login.microsoftonline.com/my-tenant-id",
validateAuthority: true,
cacheLocation : "localStorage",
navigateToLoginRequestUrl: true,
popUp: false,
consentScopes: [ "user.read" ],
unprotectedResources: ["https://www.microsoft.com/en-us/"],
protectedResourceMap: protectedResourceMap,
correlationId: '1234',
piiLoggingEnabled: true
}),
Do I need to add the webAPI to the protected ressources in Angular? Do I need an extra Application to secure the API and then allow my Frontend App to access the backend app? Reading through all the available articles confused me even more.
In your azure registration app go to "expose an api", copy the scope url and set this value as a scope in your loginRequest
var loginRequest = {
scopes: ["api://aa059cdd-1f53-4707-82a8-fdf7bd6c2859/Test"]
};
msalInstance.loginPopup(loginRequest)
.then(response => {
// handle response
})
.catch(err => {
// handle error
});

Resources