Why offline scope is added automatically in Microsoft Identity Platform - azure-active-directory

I am trying to use Microsoft Graph api's using OAuth 2.0
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=<client_id>&redirect_uri=https://mytestenv&response_type=code&prompt=select_account&scope=User.Read
Even though i provided User.Read scope. OAuth consent screen lists offline permission also.
How to remove this?

Try to read this document: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#offline_access.
This permission currently appears on all consent pages, even for flows
that don't provide a refresh token (such as the implicit flow). This
setup addresses scenarios where a client can begin within the implicit
flow and then move to the code flow where a refresh token is expected.
On the Microsoft identity platform (requests made to the v2.0
endpoint), your app must explicitly request the offline_access scope,
to receive refresh tokens.
It’s not currently possible to remove the offline_access scope from the initial consent screen when using the v2 endpoint with an AAD account. There is a feedback of this issue here.

Related

Office-Addin Single Sign On and API Scopes

The Office Addin for Excel provides the method:
OfficeRuntime.auth.getAccessToken(OfficeRuneTime.authOptions)
to call the Azure Active Directory, log in the user and gain access to the users profile. The method brings up a dialog box asking the users consent for the Office App to access their profile. The consent box also includes the grants to my Web App (Angular web site that runs in the Excel Taskpane) and includes the words "If you accept, will also have access to your user profile information"
All good. But my Web App communicates with my API, which requires an additional granting of consent for my API to access the users profile.
Is there any way to cause the dialog box invoked by 'getAcccessToken' to also grant permission to my API?
When I login using MSAL as a fallback method (not getAccessToken(), but using an excel dialog box with MSAL configured as per the various Microsoft Walkthoughts), the consent box DOES include both my WebApp and my WebAPI. And authentication works correctly.
I note that the Manifest file has a tag. I had hoped that adding the Scope to my API in here would cause the Office-Addin to request consent to it, but no banana, it does nothing.
Any Ideas?
I do note that getAccessToken() deliberately does not return an access token to MS Graph, with the Microsoft Documentation citing 'security concerns', and such access to Graph must be via Server Side Code using the On-Behalf-Of flow, perhaps similar reasoning does not permit me to gain consent to any API using getAccessToken(), but what then are these section in the manifest file for? I have really struggled to get SSO working with Office Addins, there are so many nuances and unexpected behaviours.
The getAccessToken method calls the Azure Active Directory V 2.0 endpoint to get an access token to your add-in's web application. That enables add-ins to identify users. Server-side code can use this token to access Microsoft Graph for the add-in's web application by using the "on behalf of" OAuth flow. This API requires a single sign-on configuration that bridges the add-in to an Azure application. Office users sign-in with Organizational Accounts and Microsoft Accounts. Microsoft Azure returns tokens intended for both user account types to access resources in the Microsoft Graph. Read more about that in the Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow article.
In answer to my own question,
It is NOT possible to cause the dialog box invoked by 'getAcccessToken' to also grant permission to my API
I have written a lengthy response to this in my answer to this question
Office-Addin MSAL Single Sign In SSO: How to Refresh the Access Token?

Azure AD OBO Reconsent

I'm currently developing an application which consists of a frontend SPA which makes request to a Node backend. The Node backend makes requests to MS Graph. For this usecase I set up the OBO flow which works fine.
The SPA uses MSAL.js to request a token for middle tier API with /.default scope. The middle tier API knows the client as 'knownclient' in its Manifest. On very first login the application wants the user to consent to the combined scopes from client and middle tier. (If the user never used the app before)
The problem now is the following: By going further in the development process, new scopes are added for MS Graph in the middle tier API. However the client doesn't show the consent prompt to the user for giving his consent to use the new backend scope although using the /.default scope in the client.
The first approach I had was settings prompt='consent' to the MSAL setting in the frontend. This approach works but results in asking the user for consent every time he logs in.
The intended behaviour would be to just ask for consent if the middle tier API changes its scopes.
How do I have to set up my applications to get this result?
As I said in the comments, if you just add new permissions, don't use prompt='consent', because this will cause the administrator consent page to be triggered every time you log in as a user.
When you add a new permission, you only need to grant the administrator's consent, and there is no need to request the user's consent again. So, you only need to grant the administrator consent in the Azure portal. Or, use the url that the administrator consent to: https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={client-id}.

Why do I need two AAD applications just to add roles into an access token?

As shown by many samples I have two AAD application registrations, one for my javascript-based front end, and one for my JSON-only web APIs.
If I fully trust my client AAD application, why does AAD require me to create a second AAD application for my web APIs?
For example, assuming I add specific roles to my client AAD application, if client signs in with AAD and gets an id token and access token containing my roles, it only needs to send the access token to my APIs. The API only needs to crack the JWT, validate the audience, issuer, tenant, roles permissions, and signature. In this world, no client secret is needed in the web APIs, a second AAD application registration not needed, and still no call to AAD from my APIs. Unfortunately, without two AAD applications, I cannot figure out a way to have AAD include roles into my access token.
If I didn't fully trust the issuer from mucking with claims, I can see why I would need two AAD applications and a client secret. But since I do trust my AAD application and the signature of the JWT, why the extra complexity? Or maybe there is a way to do this that I haven't found?
Thanks!
Responding to Marc here because just not enough characters in the comments field -- The sample you referenced is an excellent sample, specifically the JavaScript one calling the Web API. It is what I am doing right now in fact. However, the problem is that Web API in the sample is open to anybody who has authenticated on the tenant. I need to secure the Web API down to certain individuals in the tenant, and simply checking the client/app id is not sufficient as anybody who can create an AAD app can fake it.
So what I need to do is have roles added to the the access token so I know that my application authenticated the user, and that user has been granted the required roles. For example, here is a Microsoft sample. And even here a Microsoft video walking through the process.
If I don't have two AAD applications w/client secret, the roles claims is never provided in the access token. It is always provided in the id token, but not the access token.
I feel like I am missing something obvious here. If AAD would just put the roles I requested into the JWT when I authenticated against it, and I validated its signature, audience, issuer, and roles, I wouldn't need any of this extra complexity?
Ah, I think I understand where you are going: you would like to control which users can access an API, no matter what client app they are using to access the API with. That's a function of the API - you cannot control that through AAD. In AAD you can control which users can access which applications (UI) using either user access restrictions (enterprise tab) or role-based access. However, access to an API is controlled in AAD at the calling application level via scopes. APIs are never accessed directly by users but only by other apps so controlling access permissions at user level would cause admin havoc. So, you can control what permissions a user has in the app they are using and you can control what permissions that application (client) has in other applications (APIs, resource servers) it is using.
In other words: role is about user access to UI, scope is about one apps' access to another.
App secrets provide added security for getting tokens - they have no bearing on what permissions are included in the token.
Can you provide a link showing that two apps are needed? That should only be the case if the API you want to call is not provided by the web app which served the JS to the browser. None of the 'official' samples require you to register two apps (Graph API, used in some of these samples is a separate API and it is already registered). A problem with tokens passed from the browser is that they were acquired by a public client, not using any secrets apart from user creds. Therefore, they are easier to steal and re-use. Your own back-end app may want to use a secret to get its own token (extension grant) to call yet another API using a token that does not reside in a public client.

How to get scope list from service for specifying with client authentication request

I have a UWP app that uses WebAccountManager for AAD authentication. I also have a service, hosted in Azure, used by the UWP app. That service uses the token the UWP app sends to get another on-behalf-of token (I think that's what it's called) to then call other service APIs as the user (e.g. Microsoft Graph and Outlook REST API). In other words, UWP app calls WebAuthenticationCoreManager.RequestTokenAsync to get a token, sends it to my service, my service calls AuthenticationContext.AcquireTokenAsync to get an on-behalf-of token to use when calling the Outlook REST API, for example.
In the AAD registration for my service, the "Required Permissions" list all the services and permissions/API calls it might make on behalf of the user (E.g. "Microsoft Graph"-> "Have full access to user calendars")
When my UWP app creates the WebTokenRequest to pass into the RequestTokenAsync function, it currently passes an empty string as the value for "scope." What should it be passing for the scope parameter? Should it be passing the full and exact list of permissions that the service declares are required? If so, how do I get that permission list to the client? Just hard-code and update the list whenever the service required permissions list changes?
In Azure Active Directory, there are two fundamentally different ways to specify the permissions your app requires when authenticating.
Static Consent
Dynamic Consent
Back in the Azure Active Directory V1 endpoint, you would set "Required Permissions" to other APIs when registering your client application. This is setting up Static Consent. These permissions are fixed, and when you trigger the user to consent to these permissions, the user has to consent to them all at once. Additionally, if at some point your app wants to add new permissions to other APIs, you will need to force the user to go through the full consent experience again, which may even require special logic on your application.
This is why in the V2 endpoint, Microsoft developed Incremental and dynamic consent.
With the v2.0 endpoint, you can specify the permissions your app needs dynamically, at runtime, during regular usage of your app. To do so, you can specify the scopes your app needs at any given point in time by including them in the scope parameter of an authorization request.
Here, you can specify only the permissions your app needs to complete the flows it is trying to accomplish at that time. If you need more access, you can simply add it during your authentication experience, and it will prompt the user only for those new permissions.
Now let's return to your question. If you are using the V2 endpoint, you should be using Dynamic Consent, which means that the settings in "Required Permissions" do not really matter to you. You should be keeping the list of scopes your app requires in your app settings.
Some situations in the V2 endpoint still require Static Consent, like service to service calls with direct application permissions. For those situations you would pass the scope <resource>/.default as noted here. This might also work for delegated tokens, but it is better to just use Dynamic Consent.

Not Getting a refresh_token

This is in continuation with my other question.
I had to finally get the user in question the admin role and then I created a new application registration at https://apps.dev.microsoft.com/
The application was granted admin consent by hitting https://login.microsoftonline.com/common/adminconsent?.. endpoint with the required parameters.
Everything works fine and I was even able to create the outlook mail subscription for this user.
The issue though is, the endpoint https://login.microsoftonline.com/common/oauth2/v2.0/token is not giving me the refresh_token. I tried including the offline_access (reference - http://massivescale.com/microsoft-v2-endpoint-primer/) in the scope for getting the authorization code, but got the following error -
AADSTS65001: The user or administrator has not consented to use the application.
So the situation is like this -
If I use v1.0 endpoint, I get both access and refresh token but
hitting the endpoint
https://outlook.office.com/api/v2.0/Users('dummy#example.com')/subscriptions
sends back a 401 Unauthorized. I understand that the endpoint targets v2.0 but I didn't find one for v1.0.
However, If I use v2.0 endpoint, I am able to create the subscription but only get the access token which is shortly lived and this creates a need for going through this whole process again which I don't want.
As a commenter indicated, you've registered an Azure AD v2.0 application, and are calling the Azure AD v1.0 endpoints. This isn't strictly the problem you're facing, but I recommend reconfiguring your auth endpoints to be for v2.0.
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
I think the issue you may be running into is not configuring static permissions before calling the admin consent endpoint. One of the new features of Azure AD v2.0 is dynamic consent & scopes that allow you to ask for new permissions when requesting them; however, for admin consent you must configure these as static permissions.
You can configure static permissions in Azure AD v2.0 inside the App Reg Portal through the UI below:
Then try hitting the admin consent endpoint again, and finally re-requesting the refresh token with the offline_access scope.

Resources