Trying to access a v2 endpoint hosted webapi but no luck, true if only graph api works on v2 now? - azure-active-directory

Had a webapi running on v2 endpoint, the intent was to get access through a single call to both graph and the custom webapi, was using the v2 auth code grant flow, the url using as below,
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=14e9111f3e1-d220-415d-9bf4-d089f0b5feff&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A8081%2Fartifactory%2Fwebapp%2Fsaml%2FloginResponse&response_mode=query&scope=api%3A%2F%2F14e9f3e1-d220-415d-9bf4-d089f0b5feff%2Faccess_as_user%20https%3A%2F%2Fgraph.windows.net%2Fuser.read%20openid%20offline_access&state=12345
with the scope as
api://14e9f3e1-d220-415d-9bf4-d089f0b5feff/access_as_user https://graph.windows.net/user.read openid offline_access
However, keep failing with a invalid scope error. If I take out the custom webapi from the resource, everything went through wonderfully.
Reading further, there is a limitation for webpi that
Web API can receive tokens only from an application that has the same Application ID. You cannot access a Web API from a client that has a different Application ID.
So I am confused, how to archieve the goal to use v2 endpoint to authenticate and get access to both graph and webapi????
--edit
the error message is 'AADSTS65005: The application 'blah' asked for scope 'user.read' that doesn't exist on the resource. Contact the app vendor.'

Today the v2 endpoint cannot issue an access token for a custom API. The feature is in active development, but there's no ETA to share.
Also note: even when the feature will be available, you will not be able to reuse the same access token across multiple resources; you'll be able to consent for multiple resources at once, so that your user is only promoted once, but you will need to request access tokens for each resources separately.

Related

How authorization code flow works in single page applications?

Hi I am exploring some of the authentication and authorization flows with respect to azure active directory. I was using previously oath implicit flow in single page application. After spending time in reading microsoft documentation, I have understood following with respect to implicit flow.
Implicit Flow:
Single page javacript application uses implicit flow to get obtain access token from azure active directory. It directly calls token endpoint to obtain the token so this makes implicit flow less secure.
Authorization Folw in .Net Web application
Whenever we use .Net core web mvc application with authorization code flow, first call will happen in browser to authorization endpoint to get code. In browser we could see the request made to authorization end point. In request url I will pass response type as code then client id and redirect ui. Here first handshake take place between browser and authorization end point. This handshake returns code to the redirect uri. Next part, application has to make POST request to token endpoint to get access token. Code received in first step I will send in token request. In this request I will include client secrete also, redierct uri also. But whenever I make first GET request to authorization endpoint I will not pass client secrete. This is because Its not good to expose secrete in browser. So in second post request I will include client secrete also. Once I get access token I will add it in api request header to make secured call to apis.
This is the authorization code flow flavor I have understood with respect to .Net core web application. now I have another flavor of authorization code with respect to single page application.
Authorization Code Flow in React Web App
I have SPA react application which uses MSAL library. I have cloned sample application from github https://github.com/Azure-Samples/ms-identity-javascript-react-tutorial/tree/main/3-Authorization-II/1-call-api/SPA.
Whenever I run this application, and sign in first call will happen as below
https://login.microsoftonline.com/common/discovery/instance?api-version=1.1&authorization_endpoint=https://login.microsoftonline.com/c5ffa990-7e0a-4bf6-6c04-79ab98e05931/oauth2/v2.0/authorize
I am trying to understand this request. I have query string appended to the url authorization_endpoint=https://login.microsoftonline.com/c5ffa990-7e0a-4bf6-6c04-79ab98e05931/oauth2/v2.0/authorize so this may be used to return the code from authorization server.
Immediately next call will happen https://login.microsoftonline.com/c5ffa990-7e0a-4bf6-6c04-79ab98e05931/oauth2/v2.0/token
to get access token and in request in FormData section I could see following parameters
client_d, redirect_uri,scope,code
In code I see some code value hopefully received from authorization endpoint. anyway this api returned me access_token.
Now coming to conclusion, In .Net core web application and React SPA application both places I am using authorization code flow.
In .Net core authorization code flow I am making use of client secrete whenever trying to obtain access token. All this happen in server side in secure manner. In react also I am using Authorization code flow but I am not using Client secrete anywhere.
In react app also I am making two requests one for authorization endpoint to get code and another to get token. All this I can see in browser itself but then How can I consider this is as secure?
In .Net web app and react app both apps making use of authorization code flow but it behaves independently depends on the type of application.
After going through several documents and videos over the internet I concluded myself as
When Authorization code flow used with server side web apps like .Net core MVC, It makes use of client_secrete to get access token and this call will happen in server side so client secrete not exposed through browser to the users
When Authorization flow used SPA applications without server side support, first it will make call to get authorization code then It will make post request to get access token WITHOUT client_secrete.The only way the authorization code grant with no client secret can be secure is by using the “state” parameter and restricting the redirect URL to trusted clients.
So I am concluding myself as when we use server side web app with authorization code flow we can make use of client secrete but in case of SPA we are not making use of client_secrete.
I have understood above concepts and explained what I understood and also I listed the confusions I got after implementing 2 flavors of authorization code flow in web app and spa app. can someone help me If my understanding is correct or not, If my understanding is wrong, where exactly I understood wrong? Can anyone help me with respect to this. Any help would be greatly appreciated. Thanks
Authcode flow is an OAuth 2.0 workflow, you can use it in any kind of client (Web/mobile/SPA).
Clients should be using MSAL library to communicate with AAD/B2C with PKCE which is used to secure authorization code grants via Proof Key for Code Exchange (code_challenge) with S256 encryption.
Authcode Grant Flow spec:
If you are using B2C, your entry endpoint is:
https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?
client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6
&response_type=code
&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob
&response_mode=query
&scope=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6%20offline_access
&state=arbitrary_data_you_can_receive_in_the_response
&code_challenge=YTFjNjI1OWYzMzA3MTI4ZDY2Njg5M2RkNmVjNDE5YmEyZGRhOGYyM2IzNjdmZWFhMTQ1ODg3NDcxY2Nl
&code_challenge_method=S256
that will display the SignIn-SignUp-Social Login Form. Just navigate to this URL with you App ClientId registered inside B2C.
You also can take a look to the custom policies starter pack to adapt your workflow to your needs (claims).
If you change response_type=code for response_type=id_token you will get a Token that can be used to authenticate against your restricted resources (API's) after all login process.
Or you can use a second call to the token endpoint to get it.
Token endpoint:
POST https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6&scope=90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6 offline_access&code=AwABAAAAvPM1KaPlrEqdFSBzjqfTGBCmLdgfSTLEMPGYuNHSUYBrq...&redirect_uri=urn:ietf:wg:oauth:2.0:oob&code_verifier=ThisIsntRandomButItNeedsToBe43CharactersLong
code=XXXXXXXXXXXXX parameter is the access_code returned from first GET request.
Solutions to this is to switch to implicit flow, where there is no need of exchanging code for access token. But keeping access token in web application still vulnerable as this can be exposed using XSS or similar kind of attacks.
Other best practice is https://curity.io/resources/learn/the-token-handler-pattern/

azp Claim Missing from Azure AD JWT

I have registered an app with Azure AD and can get JWT's but I am receiving claims associated to V1 JWT's according to this whilst I am expecting claims associated to V2 JWT's.
More specifically, I would like to add the azp claim which is only available under V2.
I've followed these instructions to add azp but it is not available to add as an optional claim. I am under the impression that I'm using a version 2 app since the endpoints end with /V2 and I also have the ability to add the ipaddr which is only available for V2 apps as far as I understand.
Can anyone point me to what I am missing?
The version of the access token has nothing to do with the endpoint you use to request the token, but is related to the resource you requested. The default version of ms graph api is the token of version 1.0. If you want to obtain the 2.0 version of the token, you should request your custom api.
First, you need to create an application that represents the api, and then expose the api protected by Azure.
Next,under 'API permissions', give your front-end application access to your backend api:
Under 'API permissions' click on 'Add permission', then click on the
'My APIs' tab.
Find your backend application and select the appropriate scope.
Click 'Add permissions'.
Grant admin consent for your APIs.
Next, go to the manifest of the front-end application and set the accessTokenAcceptedVersion attribute to: 2.
Next, you need to use the auth code flow to obtain an access token,which requires you to log in to the user and obtain the authorization code, and then use the authorization code to redeem the access token.
Parse the token, it will display azp claim and v2.0 version.

How to get user info with a valid Bearer Token?

At work we are making an SPFx Web Part React client app that deploys to SharePoint as a Web Part. Our back-end is a ASP.NET Core 2.2 Web API that is secured using Azure Portal's built in Authentication feature. The front-end is using AadHttpClient that magically handles the authentication by taking the context of the current page (SharePoint) that has the user already logged in. Doing so, silent authentication occurs and the API call is successfully made with authentication successfully passed. The AadHttpClient is supposed to magically bundle up the token in the request header that gets sent to the back-end Web API. I still need to debug the live development app and see how to retrieve the Bearer Token in the back-end Web API. These are my next probable steps?
Would I just probably use 'string bearerToken = Request.Headers.....;' or 'string bearerToken = Request.Headers["KeyValue"]' to get the token itself?
Assuming I can get this Bearer Token, how can I check the caller's user information? Is it just var userName = User.Identity.Name;? Or would I or could I use the token and some how make a call to Microsoft Graph API to view the user's info?
If you are using ASP.NET Core and using default authentication then things are bit easier. From documentation you can see that several tokens are injected in the request header based on Identity provider so in your case you have to look for following headers which Azure AD injects. These headers would contain ID Token which you would need to verify the claims and get user information.
X-MS-TOKEN-AAD-ID-TOKEN
X-MS-TOKEN-AAD-ACCESS-TOKEN
X-MS-TOKEN-AAD-EXPIRES-ON
X-MS-TOKEN-AAD-REFRESH-TOKEN
Ideally all the claims are injected automatically in ClaimsPrincipal
you can find more here
Official Docs
How To extract Token

WebAPI registered in new v2 endpoint does not prompt consent screen

An app registered in the v2 app registration portal, with a webapi platform added, however when requesting the authorisation with api scope using https://login.microsoftonline.com/common/oauth2/v2.0/authorize endpoint, it directly go to the redirect url with error code AADSTS70002%3a+Error+validating+credentials. Instead if I use the graph api, everything works, not sure what did I did wrong!
The one for the webapi scope:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=222db0-0305-4f86-96cc-d283da2f5020&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%2Ftest&response_mode=query&scope=openid%20offline_access%20api%3A%2F%2Fc6599db0-0305-4f86-96cc-d283da2f5020%2Faccess_as_user
The one for the graph api:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=222db0b0-0305-4f86-96cc-d283da2f5020&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%2Ftest&response_mode=query&scope=openid%20offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Fmail.read
EDIT
This is confusing, now I put the offline and open id to the end but get another error:
AADSTS65005%3a+The+application+'v2app'+asked+for+scope+'openid'+that+doesn't+exist+on+the+resource.+Contact+the+app+vendor.
The URL I requested is:
https://login.microsoftonline.com/e0582222da8-ec2b-4c7a-b98e-2c417627657c/oauth2/v2.0/authorize?client_id=c6599db0-0305-4f86-96cc-d283da2f5020&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%2Ftest&response_mode=query&scope=api%3A%2F%2Fc6599db0-0305-4f86-96cc-d283da2f5020%2Faccess_as_user%20openid%20offline_access
And if I google this error, there is one saying:
As of today, the V2 Endpoint does not support API access other than the Microsoft Graph.
So this is not achievable? Then how come the sample works?
EDIT 2
So if I make the requested scope the client ID, it works..
I reproduced your error . but if putting the openid%20offline_access scopes after api%3A%2F%2Fc6599db0-0305-4f86-96cc-d283da2f5020%2Faccess_as_user(api scope) , it works on my side , please try :
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=222db0-0305-4f86-96cc-d283da2f5020&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%2Ftest&response_mode=query&scope=api%3A%2F%2Fc6599db0-0305-4f86-96cc-d283da2f5020%2Faccess_as_user%20openid%20offline_access
Update
The MSAL error you linked is accessing a Web API from a client that has a different Application ID , that is not supported in v2.0 endpoint . In azure ad v2.0, Web API can receive tokens only from an application that has the same Application ID. That means api://xxxx-xxxx-xxx-xxx (web api url) , the xxxx-xxxx-xxx-xxx part has the same value with your client id of client application . To achive that , you could add two platforms : one web app ,one web api .

Scope for multiple web apis

I have 2 web apis (A and B) on my b2c. Each one of them publishes their own permissions respectively (scopeA1, scopeA2) and (scopeB1, scopeB2).
On my web application (which already configured and have granted access permission on both apis and the 4 scopes), in order to get authorization code for both apis during authentication, I tried to set my OpenIdConnectAuthenticationOptionsin scope property to include the 4 scopes.
I got an error AADB2C90146: The scope 'scopeA1 scopeA2 scopeB1 scopeB2 openid offline_access' provided in request specifies more than one resource for an access token, which is not supported.
While if I specify only scopes for web api A or B, then it works as per this link
How can I get my web app to use both web apis even with granted permissions for both
Thanks for help
If the two web APIs are separate applications in Azure AD, then you need to request access tokens separately for them.
I'm not familiar with the sample you used as a starting point, but it looks like these lines are where you need to make your change:
// Retrieve the token using the provided scopes
ConfidentialClientApplication app = new ConfidentialClientApplication(authority, Startup.ClientId,
Startup.RedirectUri, credential,
new NaiveSessionCache(userObjectID, this.HttpContext));
AuthenticationResult result = await app.AcquireTokenSilentAsync(scope);
accessToken = result.Token;
You should create an app instance for each of your APIs, and acquire a token for each of them. Then, when you call the APIs somewhere else, use the correct access token in the Bearer authentication header.
I had the same issue and asked a similar question Extend MSAL to support multiple Web APIs
but i have not had an answer, basically to get around it in the short term i have made both my API's use the same authorization client ID + secret and therefore I can reuse the same scopes accross my APIS
its not what i want but if you want to use Azure AD B2C you need to get used to compromising for a while until the support is there
-- I would also say you are using an older version of MSAL which i am also using, im waiting until the version 1 release before upgrading again.
The github talks about using this format
https://github.com/AzureAD/microsoft-authentication-library-for-dotnet
Step 1: Add MSAL to your Solution/Project
Right click on your project > Manage packages.
Select include prerelease > search msal.
Select the Microsoft.Identity.Client package > install.
Step 2: Instantiate MSAL and Acquire a Token
Create a new PublicClientApplication instance. Make sure to fill in your
app/client id
PublicClientApplication myApp = new PublicClientApplication(CLIENT_ID);
Acquire a token
AuthenticationResult authenticationResult = await
myApp.AcquireTokenAsync(SCOPES).ConfigureAwait(false);
Step 3: Use the token!
The access token can now be used in an HTTP Bearer request.

Resources