How to get microsoft graph token without popup user login page? - azure

I need to write a backend app to read & write one company emailbox.
I have registered Active Directory Application and granted Delegated permissions (read and write to user mailbox).
Question is how to get the token needed for authenticate the graph api calls(for example ListMessages).
From the document I coundn't find any working example for backend app aquiring token and make api calls.
There are two endpoint versions:
Azure AD and Azure AD v2.0 endpoints;
And two authentication method:
1. Get access on behalf of a user
https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_user
2. Get access without a user
https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service
What shoud I use ? Really confused.
Thanks all.

According to your description, I assume you want to get an access token without user login page.
Based on my test, we can get an access token that run as a background services or daemons.
It requires administrator to grant the access permission once, then user will not see login popup window anymore.
For more detail, we can refer to this official document.

Sounds like you are looking for Resource Owner Password Credentials grant flow.
However its usage is not recommended.
It does not work in these scenarios:
User has MFA
User password has expired
User is federated (MS account/Google/on-prem AD)
The only scenario that I can think of where this flow is okay is integration tests of APIs where you need to test scenarios where you call your API on behalf of a user.
Here is a better way to do what you want:
Require an application permission to access user emails and have the admin grant it. Now you can use client credentials grant flow to get a token anytime you need one.
Use delegated permissions, have the user sign in once with Authorization Code grant flow. Then exchange the code for an access token and a refresh token. Store at least the refresh token somewhere secure. Use refresh token whenever you need a new token.
The first approach is more reliable but requires broader permissions.
The second has tighter security (only users who have authorized access can have their email read), but has slightly less reliability.
Refresh tokens can be invalidated, in which case you'll need the user to login again.

Related

Restricting user scopes by using an on-behalf-of flow with Azure AD

I have a SPA React application which use MSAL for logging users in and acquiring tokens for querying MS Graph. Currently, when the user is created he/she can have two different roles, namely:
Administrator
Viewer
As is, every user is allowed to get the same scopes from AAD - Regardless of whether they are one or the other role.
This presents a problem - Because any of the users potentially have the same permissions when calling MS Graph, i.e. they could acquire the token themselves and request graph with full scopes.
The viewer role should only be able to have the [User.Read] scope, while the administrator should be able to alter every aspect of Azure AD.
Additionally, the administrator should be able to perform actions in MS graph that isn't supported by delegated permissions, i.e. creating new users.
The following makes me think that I may need to rethink the way that users are requesting resources from MS graph - which lead me to thinking that the on-behalf-of flow would be an interesting option.
As I imagine, the flow would work as follows (from when a user logs in, and requests to create a new user in my SPA)
User logs in with MSAL in my SPA
User gets the least privileged scope, i.e. [user.Read]
User creates a new user
SPA sends a request to my Web API with the users' token as bearer
Web API validates the user token with AAD
Web API validates that the user has a role of "Administrator"
Web API gets a token with ["User.ReadWrite.All", "Directory.ReadWrite.All"] scopes
Web API calls graph with the fetched application scopes on behalf of the user
Web API returns the data to my SPA
Since I'm fairly new to this world - I'm wondering if my way of thinking makes sense. In particular, I'm curious if it's really possible to request elevated permissions ["User.ReadWrite.All", "Directory.ReadWrite.All"] on behalf of a user with only the [user.Read] scope from my Web API.
Additionally, I'm of cause open for any suggestions for alternative ways to solve the above issue.
Scopes (delegated permissions) apply to an application, not a user.
Fundamentally, no matter what scopes the user gets in their token, they cannot do anything they were not already able to do.
Microsoft Graph API checks the scopes to check the application's permissions, and then checks the user's permissions to see if they are also able to do the operation.
Thus a user can never elevate their permissions through scopes.
If you have any of your own APIs, you should also handle authorization in a similar way.
If scopes are used, also check the user's permissions.
In case of application permissions (app roles with member type application), there isn't a user so your API would only check these permissions.
This is why you need to be extra careful with authorization if your back-end uses application permissions instead of on-behalf-of flow; since they don't include the user, it could allow them to elevate their privileges through your application.

Revoke access or refresh groups and roles from Azure AD in .NET Core Web App

I have a file>new .net core web app which is using Azure AD for authentication which works fine out of the box.
I have a requirement to create some auth policies so I have the following code which check the groups in the users claims and sets up an "Admin" policy which I can use on my endpoints.
services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy => policy.RequireClaim("groups", "XXXXX"));
});
This works fine too. The problem is once the user is logged in, how can I:-
Revoke access if I needed to? (e.g. a user is removed from AD or has his access revoked)
Refresh the auth so that if there has been any change in claims, roles, groups etc, it is detected.
I took a look at https://learn.microsoft.com/en-us/azure/active-directory/enterprise-users/users-revoke-access but it doesn't give much. It actually says "It's possible that the app may never send the user back to Azure AD as long as the session token is valid."
How is the best way to handle this?
To summarize the comments and post as an answer:
As I said in the comments, if you need to revoke a user's access rights, then you can do this by revoking the user refresh token. After revoking the user's permissions in Azure, then revoke the refresh token and redirect the user to the login page.
After the user is authenticated, he will receive the access token and the refresh token.
First, you need to revoke the user's refresh token. The lifetime of the refresh token is 90 days by default, so you need to revoke it during its lifetime. You can use AAD Power Shell:
Revoke-AzureADUserAllRefreshToken -ObjectId "a1d91a49-70c6-4d1d-a80a-b74c820a9a33"
But as far as I know, the access token cannot be revoked. The default expiration time of the access token is 1 hour. After 1 hour, the user will automatically lose access to AAD.
If you want to terminate user access immediately after the user permissions is revoked, you can try the continuous access evaluation provided by Microsoft, which helps ensure invalidation of access tokens in near real time. However, as the documentation says, this may cause security issues, so I think it is not the best method.
So I think the best way is: just revoke the refresh token, and then wait 1 hour for the access token to expire, the user will automatically lose access to AAD. Then refresh the authentication and redirect the user to the login page.

Microsoft Azure OAuth ID Token In Client Credentials Grant

I ideally want to be able to have an admin grant application permissions for my app and login to said app in the same flow. Is this possible?
I currently use the code grant flow for authentication.
I then use the client credentials flow for authorisation.
Is it possible to combine the two into a single flow?
I have the first redirected immediately to the second if the client token has not be granted before, but it isn't the most appealing flow from a UX perspective.
If I could add an ID token to the the client grant response that'd be perfect (I just need the UPN of the admin that is consenting), but this doesn't seem to be possible.
A key requirement is the application permissions as my app makes changes to the entire org - obtaining the grantee's ID in the same flow is just a UX optimisation.
Perhaps this is possible with the OpenID Connect flow?
Is it possible to combine the two into a single flow?
No, these are two different authentication flow.
For the authorization code flow, It's used to perform authentication and authorization in the majority of app types, including single page apps, web apps, and natively installed apps. The flow enables apps to securely acquire access_tokens that can be used to access resources secured by the Microsoft identity platform endpoint, as well as refresh tokens to get additional access_tokens, and ID tokens for the signed in user. This flow is usually used in scenarios with user interaction.
For client credential flow, it is that the administrator directly grants permissions to the application itself. When an application provides a token to a resource, the resource will force the application itself to have the permission to perform operations. This type of grant is usually used for server-to-server interactions that must run in the background and do not require immediate interaction with the user. This is generally used in daemons, which can only obtain access_token for accessing resources.
Perhaps this is possible with the OpenID Connect flow?
This is where a user is logged in. Generally, delegated permissions are used, so it is impossible.
So, in summary, you cannot obtain ID tokens when using the client credential flow because there is no user interaction in the flow.

Access token and authentication for guest user

TLDR:
is it possible to have guest account, like guest#organization.onmicrosoft.com, at company's MS Office 365 cloud that will have "read" permission to organization's users calendars and events with constant access token? By constant access token I mean that I sign in once for this guest user and receive constant access token from Azure AD (like application access authentication but as guest account).
I have my own company's MS Office 365 account with some users in it. There is one global administrator account and few regular users.
There is second company, let's call it XYZ, with their own MSO365 account with many of administrators and users. Big company.
Now I'm writing simple app where I need to have access to read XYZ company's users calendars and events. I have list of required users in my app with proper MSO365 ID's.
I think that 'read' privilege is enough since we can send invitation for events through ordinary email message.
My App will read user events through MS Graph API etc. with some logic and realease it (send invitations for events etc.) with CRON jobs.
And here is my problem with authentication.
I don't want to have "application access" Azure AD privileges at my App. I know the XYZ company security policy won't apply it since "application access" gives access to all accounts at organization. Application access means that XYZ company's global administrator apply application privileges for my App by single sign in into Azure AD. If he do so i have Access token which i can use for API calls at my app withoud need of additional authentication.
I can't use "user access" Azure AD authentication neither.
Due to my CRON jobs and API calls which fire then.
User access means that user need sign in at Azure AD login service what gives me Access token and Refresh token for API calls. Those tokens are 1 hour lifetime.
So I though about: if there is possibility to have a guest account at XYZ company's MSO365 that would let me use authentication mechanism like the "application access"?
By this I mean that XYZ company's global Admin creates me a guest account like guest#xyz.onmicrosoft.com which will have access to read users calendar and events. What is more I need this account to have constant access token which I can use in my cron job's api calls with no need to sign in at Azure AD.
The question is: is it possible? If so how to do it?
The only way there (AFAIK) is to use refresh tokens.
Application-level access is more robust but requires organization-wide access.
So you use delegated access (user access), store refresh tokens somewhere.
You can use those tokens basically indefinitely,
however certain events can expire the refresh token.
It doesn't happen often, but it can happen.
In that case you would need the user to login again so you can get a new refresh token.
You should also store the new refresh token that you get when you acquire tokens using a refresh token.
This new token can overwrite the old token for that user.
And of course keep in mind refresh tokens are user-specific so you gotta store one for each user.
This is the approach that one of our bigger apps takes.
If we fail to acquire a token in the background process,
that user gets a flag set on them that their token does not work,
and they'll get a notification that they need to re-authenticate for the feature to start working again.

Revoke consent using Azure v2.0

I am using Azure v2.0 for user authentication. The access token that I receive is used to fetch onenote content using microsoft graph api. And I do store refresh token at my end to access content on behalf of user at any time. Now user opt's out of my system I want to revoke the permissions given by user to my app.
How I can revoke the access without depending on user for that. User may not manually go and revoke the permissions. Is there any api provided for same purpose.
Is there any api provided by Azurev2.0 for the same
Sorry for the delayed response here. Unfortunately we don't have a specific revocation API. And while this is theoretically possible through existing APIs, where the oauth2Permission resource type holds the consent grant (see https://developer.microsoft.com/en-us/graph/docs/api-reference/beta/api/oauth2permissiongrant_delete), your app will need to be granted a privileged permission to perform this action. Contrary to the linked topic, I don't believe that the Directory.ReadWrite.All application permissions actually allows this operation.
Please create a UserVoice request to ask for this API.
Hope this helps,

Resources