How to get on behalf of SharePoint access in Teams app - azure

https://github.com/OfficeDev/msteams-tabs-sso-sample-nodejs
I'm trying to change the final request of this sample to access the SharePoint REST API
I've added delegate permission in AzureAD and added the scope "https://microsoft.sharepoint-df.com/AllSites.FullControl" to the token request, but still getting 401

Copping the answer from #Hilton's comments for better visibility
Modify the consent popup with the correct sharepoint scope request. Based on the name, is request Graph SSO permissions, in particular OBO permissions. I don't think you can use SSO in this way for Teams - you'll need to explicitly use MSAL and request the permissions for your app. Depending on what you're trying to do though with SharePoint.

Related

Best way to authorize with AzureAD app registration: roles or group claims when only one AD group is required for access

I have an AzureAD application registration for my front end SPA. I am using Angular with Microsoft’s #azure/msal-angular v2 authentication library. My app registration has all the necessary redirect URIs and configured for proper OAuth2 OpenID Connect using authorization code flow with PKCE. My app is using the Microsoft Graph API with only the User.Read scope. I can authenticate just fine. If my app, however, is only available for one group of people, defined by an AD group and assigned to the Users and Groups section in Azure, what is the best way to validate the logged in user is authorized? I’ve tried enabling optional group claims for the access token, but those don’t come through for some reason. I then tried adding roles-I have an “admin” role, which is the only one I need. This role is assigned to the AD group I mentioned earlier. The roles claim does come back, and I can use that, but this seems silly when I should be able to just validate if the logged in user is in my AD group. The roles approach does have the nice feature of just assigning users different roles to validate authorization for development purposes, but not sure if there’s a better way.
At some point there will be an API I need to plug in. Would it be best to get the claims from that and use that for validation?
Is there a scope or setting I’m missing? Am I achieving this all wrong? Thank you to all who reply.
At this point, you have a SPA that calls a MS 1st party API, which is MS Graph.
Since you are acquiring an accessToken to MS Graph, this accessToken can not be changed - it is meant to be decoded and validated by MS Graph itself, so you will not be able to add any extra claim on that token since you do not control the resource.
Also, your client should treat the accessToken as an opaque string, you should never rely on any claim from the accessToken on the frontend.
You can read more about it here:
https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens
If you want to do some sort of authorization on the frontend, like deciding which routes your user will have access to, you need to rely on the idToken. For the idToken, you can enable the Groups claim and get a list of groups that the user is a member of.
If, as mentioned, later down the line you need to create a custom API and call it from your SPA, then, on that scenario, you can indeed add the Groups claim to the accessToken, because it will be a resource that you control, and then authorize the requests that hit your API based on that claim
MS has a sample that shows exactly how to use security groups for access control, using an Angular frontend with a .NET Core Web API. Give it a check here:
https://github.com/Azure-Samples/ms-identity-javascript-angular-tutorial/blob/main/5-AccessControl/2-call-api-groups/README.md

MSAL PublicClientApplicationBuilder with AzureAD external user cannot access SharePoint

We have a Windows Application using MSAL with PublicClientApplicationBuilder to access SharePoint with the delegated permissions of the logged on user.
When our code is used with a login of a user who was invited as an external user in another AzureAD and his user is added to the members of a SharePoint site collection, we get an access token which results in HTTP 401. Using a user from the other AzureAD directly to log in does work. It is just with external user, we fail to get access.
When the user logs into SharePoint in the browser, using his external user login, he can access the other tenants SharePoint. So his external user account has permissions on that site collection, but it works only in the browser, not from our MSAL client.
Some details:
We created the app registration as multi tenant app in our AzureAD with the needed read and write permissions from the SharePoint delegated permission list.
An admin of the other AzureAD consented the delegated permissions for all users and we did the same in our AzureAD. So no matter which user tries to login and use the app will find consented permissions.
We use this code to get a public client app:
var clientAppId = "our-app-clientID";
var redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient";
_clientApp = PublicClientApplicationBuilder.Create(clientAppId)
.WithRedirectUri(redirectUri)
.WithLogging(Log, LogLevel.Verbose, false)
// .WithTenantId("we tried our and the other tenants ID")
.Build();
The commented line .WithTenantId was just added while we tried to find a solution.
We can see that it makes a difference for the token content. Without that line or with our tenantId we see the users "oid" is the objectId from the user in our AzureAD.
When we use the tenantId of the other AzureAD, we get the oid of the external user object in that other AzureAD.
So we had hopes that the latter call would succeed, but it fails as well, this time with HTTP 403. So the user token seems to get a bit further, but still not to the SharePoint site collection.
Any idea if this scenario is possible?
Would be nice, if possible and best if we would not have to call WithTenantId because otherwise we would some need to lookup the correct tenantId on the client machine - not sure where to get it from, except asking an admin from the other tenant and putting the value in some app config file or the Windows registry.
• The issue most probably according to your description suggests that the scopes might not be added correctly to the ‘Sharepoint API’ because since you are accessing the sharepoint site from a public client using MSAL authentication, the scopes/permissions to access the sharepoint site from a public client in Azure AD needs to be added and extended to service the requests from external user accounts also.
To do so, you need to add scopes/permissions to Sharepoint API through the Azure portal as when you are calling SharePoint APIs outside of the Microsoft Graph, you call ‘/_api/web/lists’ and it will retrieve all the lists. Thus, if your public client app performs this action using the Microsoft Graph API permissions then you will get an access denied error message as you are encountering HTTP 403 error.
• Thus, in your case, to access the sharepoint sites, you will need to add the scopes ‘AllSites.Read’ and ‘Sites.ReadWrite.All’ to the Sharepoint API for your public client app as the scope for ‘Sites.Read’ in the Microsoft Graph API isn’t enough for it. Also, ensure to add the ‘https://<domain>.sharepoint.com/AllSites.Write’ and ‘https://<yoursite>.sharepoint.com/Sites.ReadWrite.All’ scopes also to the Sharepoint API for that public client app.
To access the Sharepoint API through public client, you use AAD auth for which Microsoft recommends using a certificate rather than a secret. For more information regarding this, kindly use the below documentation link: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-authentication-flows#client-credentials
• Also, ensure that ‘https://microsoft.sharepoint-df.com/Sites.Search.All’ and ‘https://yourtenant.sharepoint.com/Sites.Search.All’ are also added as scope in your application as Sharepoint online site might reject the token because of invalid audience.
For more information regarding the scope modification, kindly refer the below link for more details: -
https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/400

Why is an Azure permission missing from the scopes of my JWT token?

I have a problem regarding the permission granted to my app by the user showing up as a scope in my JWT.
I want to allow the user to see a list of his tenants (Office 365) on my page. For this I need a token with the https://management.azure.com/user_impersonation scope. I added the permission to the Azure API Permissions. When the user first logs in he sees this:
From this screen I assume my setup works, since the user gets asked to grant my app permission for what I need (Access Azure Service Management as you). But when I paste the JWT on the JWT Debugger I don't see the scope user_impersonation among the scopes.
I get this:
I already tried to remove the app from the test-user's applications (in their Azure Portal) to get it to ask again for consent but it's still the same. Other test users have also the same result.
What I'd need is simply to see user_impersonation among the scopes. That would allow me to call the API endpoint that returns a list of my user's tenants.
You need to acquire the access token for the https://management.azure.com resource.
Or if using v2, request it for the https://management.azure.com/user_impersonation scope.
That looks like an MS Graph API token.
An access token is always only valid for one API, so you need to ask for a token for the Azure Management API.
It works now!
So, I tried to get scopes for both https://management.azure.com/ and https://graph.microsoft.com/ in one single token. As Juunas explained, you have to get a separate token for each API. But can ask consent for both at the same time though.
My flow is this now:
I log the user in while asking him to consent to some permissions (for both API's and on first login only)
I request a token in the background for the Graph API scopes
I request a second token for the Azure Management API scopes

Generate MS Graph Outlook Task Access Token from Sharepoint

I want to read all the Outlook Task assigned to the logged in user from with an Office365 web part (SPFX), But I do not want the user to sign in again or do any such operation, Ideally what I want is to use SharePoint context to be used to authenticate the user.
I came across the GraphHttpClient which uses /_api/SP.OAuth.Token/Acquire to acquire an access token which can be used with Microsoft Graph but, by default, this method only issue Group.ReadWrite.All and Reports.Read.All permission.
I need to grant it Tasks.Read permission.
I was wondering if there is any way to pass the Scope into the method to get an updated token?
I have already tried passing Scope as a query string to URL and as a header, both yielded me no result. Any suggestions on how to tackle this issue will be helpful.
The GraphHttpClient has been deprecated, you want to use the new MSGraphClient instead.
By default, MSGraphClient doesn't have any permission scopes applied other than User.Read. It does, however, support requesting additional permission scopes from the tenant administrator. The overview for how this works can be found at Connect to Azure AD-secured APIs in SharePoint Framework solutions.

Azure AD + Graph API: How to reconsent after new permissions?

I have an application registration in Azure AD which has some Graph API delegated permissions set for it.
The application is simply a page in SharePoint that is making the Graph calls, authenticating with the ADAL.js library.
I now want to make an additional Graph call on the page to a new Graph API endpoint so I need to assign the application an additional permission. I set this permission in Azure AD and save. However, the user accessing the SharePoint page is never asked to reconsent to the new permissions, therefore the new Graph call fails with a 401 Unauthorised message.
I have tried this with a number of different endpoints and permissions, and I am sure I am setting the correct permissions in the application.
How can I have the consent dialog appear for users automatically when the application permissions change?
Admin consent is not an option.
I remember having a discussion about this with a member of Azure AD team some time back and this is what he had suggested at that time (though I never tried it so it may not work).
Essentially what he suggested is that when you get Unauthorized (401) error, you redirect the user to Azure AD login again i.e. follow OAuth authorization flow again but include prompt=consent in the sign in URI. This will present the user a consent page with latest permissions. Once the user consents to the latest permission, you can redirect the user back to your application. You may find this link helpful for understanding different values for propmpt parameter: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code.
Again, I have not tried this personally so it may not work. If it doesn't, please let me know and I will remove my answer.

Resources