Azure AD OBO Reconsent - azure-active-directory

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}.

Related

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.

Why do i need to create a Multi-Tenant App?

I have been doing some R&D on using the MicrosoftGraphAPI to fetch the skus subscribed by my organization.
I have created an app as described in the documentation. I did all the steps in the above link except 'Assign application to role'.
Using postman am able to get the oauth2 token by sending a post request using the link
https://login.microsoftonline.com/<mytenantid>/oauth2/token
with the client_id, client_secret, resource(https://graph.microsoft.com) and grant_type(client_credentials) parameters.
After this token is obtained I can fire a get request https://graph.microsoft.com/v1.0/subscribedSkus with the Authorization header set as Bearer {token} which will return the SKUs subscribed by my organization.
So far so good. :-)
Now the requirement is I need to fetch the subscribed SKUs by one of the client (let's say having the azure ad tenant id 'ABCDEFG') of my organization.
I can successfully do that by registering an app in the client's tenant 'ABCDEFG' with the same steps as above.
This approach is fine if my organization has say 1 or 2 clients.
However, if the client numbers are more than say 30 this approach of registering an application in each Azure AD instance is not feasible.
If the application that I registered in my organizations AAD was multi-tenant then how should it help me?
What will be the steps needed to obtain the access token for each tenant?
Can somebody assist with some detailed explanation?
Since you need application-level access, you would assign one of the Application permissions listed in the documentation for getting SKUs: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/subscribedsku_list.
Directory.Read.All, Directory.ReadWrite.All
In this case you should require the Read Directory Data (Directory.Read.All) application permission.
Then you mark your app as multi-tenanted.
Now then in order for another org to use your app, they will have to be on-boarded.
You will need some kind of page where their administrator can click a button/link to start using your app.
This should redirect the admin to:
https://login.microsoftonline.com/common/oauth2/authorize?client_id=your-client-id&prompt=admin_consent&response_type=code+id_token&redirect_uri=url-where-to-send-user-back
Once they sign in, they will be presented with a consent screen, where they can approve the permissions that your app requires.
If and when they do that, they will be redirected back to your app (to the URL you specified) and you can use the Id token to know which Azure AD tenant registered.
During this process a service principal for your app is created in their tenant, and the required permission is granted to it.
This means you can then get an access token for their tenant from: (using the same credentials)
https://login.microsoftonline.com/their-tenant-id/oauth2/token
Remember that access tokens are specific to an Azure AD tenant, so you will have to get an access token for each tenant.
One thing I would like to point out is that you should instead try to use delegated permissions if possible.
The application permission given here gives quite large access to your app, and some admins might not use your service for that reason alone.
Delegated permissions are more complex to handle, but allow your app to act on behalf of a user instead of purely as itself.

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.

Connect a salesforce user to another salesforce user in another org without any user intervention

We would like to connect a salesforce user to another salesforce user in another org without any user intervention from a service.
We have tried SAML Bearer Flow (using Remote Access Application) to connect to salesforce to retreive Access Token for one of our product. We are referring to the follwoing article.
http://help.salesforce.com/help/doc/en/remoteaccess_oauth_SAML_bearer_flow.htm
As referred by the SF article for this flow, it uses a previous user authorization to connect and retreive Token. In case the user (for whom Token is requested) has not already authorized the App, SF takes you to the Authorization page first and app will get the access token once app is authorized. This is working fine too. However it has this painful step of users authorizing the app before we can use this flow for the product. It would be good and simplified if this step can be done once for an org and the article does mentions that either User or Admin can authorize the app. However I am not able to find how an Admin can authorize the remote access application.
Does anyone knows and can guide how can an Admin authorize an App or is thre any other way we can achieve our requirement. Any thoughts will be really appreciated.
OAuth1 and OAuth2 require user intervention by design. Anything you do to defeat this would be circumspect and not best practice. You could make it easy on the user, but you will always have the initial "Authorize this app" message.
If you are trying to make it easy for the user to login to either org, then you may want to consider a hub-and-spoke SSO solution. See this doc.
If you are trying to pass information between two Salesforce instances, then you may want to consider Salesforce2Salesforce, or outbound workflow. However, this is done at system context, not user context.
If you want to maintain user context and security, you should consider the new Salesforce Canvas API. Canvas allows you to call an outbound service, and pass credentials to the service so that it can communicate back. There is no reason the foreign service could not be a Salesforce instance.

Resources