When should I select openid or email as scope in msal.js executin in browser - azure-active-directory

I have an entirely client side web page that makes ajax calls to Microsft ASP.NET Core client REST services. Both this UI application and the web service are registered in Azure ActiveDirectory tenants. I have successfully used another ASP.NET Core app registered in the directory to do user authentication and then request a JWT token for the web service and authenticate against that. Nowhere is the ASP.NET Core Authentication code did I have to specify scopes anywhere. If I wanted to call the graph API, I requested a token for https://graph.windows.net and used that.
Looking at this sample, which I made work in my AD, requesting a token for 'user.read' seems to be necessary. However, other samples just use ['openid'] or ['openid', 'email']?
I know that user.read is the AzureAd pernmission to read my entire user profile with the graph api. Does that imply whatever openid and email gives me?

The openid and email scopes are used in Azure AD v2 applications to get access to different info. They are not needed in v1 applications.
Quoting from documentation:
If an app performs sign-in by using OpenID Connect, it must request the openid scope. The openid scope shows on the work account consent page as the "Sign you in" permission, and on the personal Microsoft account consent page as the "View your profile and connect to apps and services using your Microsoft account" permission. With this permission, an app can receive a unique identifier for the user in the form of the sub claim. It also gives the app access to the UserInfo endpoint.
And about the email scope:
The email scope can be used with the openid scope and any others. It gives the app access to the user's primary email address in the form of the email claim.
User.Read is a scope for the Microsoft Graph API. Actually the fully qualified form is https://graph.microsoft.com/User.Read. But MS Graph API is a special case :)

Related

Graph API POST Request (Create List Item) 'accessDenied' error for Guest AD Users

I have quite a strange issue (well I think it is)... I'm building a web application using Ionic Angular and this application needs to submit information to a SharePoint site within our company. Authentication for the application is handled using Microsoft Authentication Library for Angular (v1) and the users of the application can either be AzureAD Guest users, or actual company users. The application successfully authenticates both types of users and they are issued an IDtoken, along with an accessToken. The access token is then used to perform GET, PATCH and POST Graph API requests against particular lists within a SharePoint site.
If I'm logged in as a full user... there is no issue, the app can successfully perform all three request types against the lists. However, if I'm logged into the application as a Guest user, I can only successfully perform GET and PATCH requests, but not POST:
A Postman POST request using the access token retrieved via MSAL authentication
I have checked the scopes within the token using https://jwt.ms and confirm that the following scopes are present:
Sites.Manage.All
Sites.Read.All
Sites.ReadWrite.All
User.Read profile openid email
The permissions for the lists are granted through membership of an Azure AD Domain/Security group and both; the full user and guest user are members.
To further add to this, I've logged into the SharePoint site online as the Guest User and I can successfully See, Add and Edit List items from the list, but I can't seem to do this via the Graph API.
Has anyone seen this behaviour before, or has any pointers?
Thanks in advance.
This is my app registration setup regarding permissions:
API Permissions
Please check your permissions in Azure Portal. When getting the access token with a signed-in user, you need to make sure the delegated permission Sites.ReadWrite.All has been set, and grant admin consent for your tenant.
And the scope should be added this permission for requesting an access token.
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
client_id=<client_id>
&scope=https%3A%2F%2Fgraph.microsoft.com%2FSites.ReadWrite.All
&code=<authorization_code, see https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#request-an-authorization-code>
&redirect_uri=<redirect_uri>
&grant_type=authorization_code
&code_verifier=ThisIsntRandomButItNeedsToBe43CharactersLong
&client_secret=<client_secret>
It may be a delay about 5-10 mins after adding the permission.

How to authenticate to personal OneDrive with Graph REST API

I'm trying to write an R package to let users access the files in their OneDrive folders from R. The API is Microsoft Graph.
Everything is working fine with OneDrive for Business (which is basically SharePoint under the hood, as I understand it). However, I can't get it to work with personal OneDrive.
Custom app registration, consumers authorization endpoint
When I use an app registration under my own AAD tenant, I get the following error from the consumers AAD authorization endpoint:
AADSTS50020: User account 'xxxxx#gmail.com' from identity provider 'live.com' does not exist in tenant 'Consumers' and cannot access the application 'd44a05d5-c6a5-4bbb-82d2-443123722380'(AzureRtest_cli) in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.
Custom app registration, 9188040d-6c67-4c5b-b112-36a304b66dad endpoint
From this page it appears that the token should be for the tenant 9188040d-6c67-4c5b-b112-36a304b66dad instead of the generic consumers. When I tried that, I obtained a seemingly valid token. However, talking to the https://api.onedrive.com/v1.0/drive endpoint results in a cryptic 401 error.
Azure CLI app registration, consumers endpoint
As a hack, I tried piggybacking off the Azure CLI's app registration. This fails with
AADSTS65002: Consent between first party application '04b07795-8ddb-461a-bbee-02f9e1bf7b46' and first party resource '00000003-0000-0000-c000-000000000000' must be configured via preauthorization. Visit https://identitydocs.azurewebsites.net/static/aad/preauthorization.html for details
Azure CLI app registration, 9188040d-6c67-4c5b-b112-36a304b66dad endpoint
Finally, I tried using the CLI app registration with this tenant, which also failed:
unauthorized_client: The client does not exist or is not enabled for consumers. If you are the application developer, configure a new application through the App Registrations in the Azure Portal at https://go.microsoft.com/fwlink/?linkid=2083908.
What are the exact steps I need to do to get to my personal OneDrive?
It turns out I had a bug in my code: I was using the tenant consumers.onmicrosoft.com instead of consumers. The process to communicate with Graph for personal OneDrive that worked for me was:
Use the authorization code flow as described here, with the following specs:
tenant: consumers
client id: for my custom app registration
scope: https://graph.microsoft.com/{scope} offline_access openid where the scope is one of those listed here
Use the API endpoint https://graph.microsoft.com/v1.0.
With regard to that last point, note that the documentation here is incorrect or at least outdated, as it still gives https://api.onedrive.com/v1.0 as the endpoint for personal OneDrive requests.

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.

Accessing Intune graph api using send-on-behalf authorization gives response as unauthorized

I Followed the Active Directory .NET WebAPI onBehalfOf sample.
In the web api created another endpoint to access Intune app protection policy from url
https://graph.microsoft.com/beta/deviceAppManagement/managedAppPolicies,
in azure provided permission to app to access Graph API.
In the call to AquireTokenAsync changed the resource Id to https://graph.microsoft.com/.
This returned the JWT token that contained:
"aud": "https://graph.microsoft.com/",
"scp": "DeviceManagementApps.ReadWrite.All User.Read",
However fetching the endpoint
https://graph.microsoft.com/beta/deviceAppManagement/managedAppPolicies
Returns an HTTP response of 401 Unauthorized.
What is missing?
This generally implies one or both of the following issues:
You need to obtain Admin Consent. The DeviceManagementApps.ReadWrite.All scope requires that an Admin consent to the permissions before a normal user can can authorize the scope.
You're app's registration doesn't have the correct scopes defined in Azure. Make sure your registration is selection scopes for Microsoft Graph and not Azure AD Graph API. These are two distinct APIs and the differences are greater than simply the resource URI.
Also note that the Client Credentials grant (aka Application scope) isn't supported by the Intune APIs. You can only call these endpoints using Delegated permissions (Authorization Code or Implicit grants).

Server-side OAuth for user impersonation via GMail API

I am trying to perform server-side OAuth so I can use a specific user account in my domain to send emails (hence using GMail API) via my application.
Mine is a purely server-side app and I cannot perform "user consent" via a UI.
I have created a project in Google App Engine and have obtained service account credentials (P12 key).
My code looks like this -
new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(googleEmailerServiceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(googleEmailerServiceAccountPrivateKeyLocation)).setServiceAccountScopes(Collections.singleton(GmailScopes.GMAIL_COMPOSE))
.setServiceAccountUser("xxx#xxx.com")
.build()
I have delegated domain wide access to the application (for GMAIL COMPOSE scope) via the admin console as per https://developers.google.com/identity/protocols/OAuth2ServiceAccount.
And I still get an Unauthorised 401 when I try to send emails from my app.
Since there is no explicit documentation for the Gmail API that says it allows domain wide delegation, I am guessing it is not allowed for Gmail.
Is there any way of achieving this programatically?
Any idea would be much appreciated.
Thanks!
As far as I know you cant use a service account with Gmail. Service accounts must be pre authorized.
Authorizing Your App with Gmail
All requests to the Gmail API must be authorized by an authenticated
user. Gmail uses the OAuth 2.0 protocol for authenticating a Google
account and authorizing access to user data. You can also use Google+
Sign-in to provide a "sign-in with Google" authentication method for
your app.
Share a Google drive folder with the Service account. Add the service account email as a user on a google drive folder it has access
Share a Google calendar with the service account, just like any other user.
Service accounts don't work on all Google APIs. To my knowledge you cant give another user access to your Gmail so there will be now to pre authorize the service account.
Recommendation / work around / hack
Create a dummy app using the same client id, authenticate it get the refresh token then use the refresh token in your application.

Resources