How to configure Azure AD Oauth2 to return all user groups on login - oauth-2.0

I have an AD registered application which has an integration with Azure AD for SSO. It uses the Oauth2 strategy, by using the omniauth-azure-activedirectory-v2 gem.
I want to map a users security groups to my applications authorization model and for this I need the names of the security groups.
I want to reliably get a users security groups and the group names on login and I'm not able to. I get them sometimes correctly, sometimes in a uuid format and sometimes not at all.
I have an optional group claim set up for my application in Token Configuration and configured to return sam_account_name for all attached groups.
This seems to work fine for some clients, the groups are returned as for example "Admin_APP", but for others I seem to have the following issues:
A Users groups are returned but only as a ID(c5bb3738-59f1-4718-b34c-2dfac761e023), even tough I requested the name.
A User has "readable groups" but not all assigned in AD, some are missing.
Is this a configuration on my application side or should the organization adding my application to their AD configure their groups or my application? Or should I not rely on the token cliam at all and fetch the groups using the GraphQL API Azure offers?
I noticed when adding the application myself I need to give permissions for my user.profile but it doesn't show allowable permissions for groups. Also in the Enterprise application tab for the organization under permissions I can't seem to find the group claim I added. Only openid, profile and email.

I tried to reproduce the same in my environment and got the results like below:
I configured the Optional claims in Azure AD Application:
I generated the access token via Postman by using below parameters:
https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
client_id:ClientID
client_secret:ClientSecret
scope:user.read openid
grant_type:authorization_code
redirect_uri:redirectUri
code:code
When I decoded the token, I got the Group IDs instead of Group Name like below:
Note that: If you are configuring sAMAccountName as the claim value in the token, then it only returns the Group which is synced from on-premises AD. By default, Group ObjectID is returned in the group claim value.
By default, groups emitted in a token is limited to 150 for SAML
assertions and 200 for JWT.
I agree with junnas, you can make use of Graph API to get the user groups like below:
https://graph.microsoft.com/v1.0/users/UserID/memberOf
To get the only list of security groups user belongs to, you can make use of below query:
https://graph.microsoft.com/v1.0/users/UserID/memberOf?Filter("mailEnabled eq false and securityEnabled eq true")
References:
List a user's direct memberships - Microsoft Graph v1.0 | Microsoft Learn
How to get groups to appear as claims in the access_token by AmanpreetSingh-MSFT

Related

OAuthPrompt/SigniIn for AzureAD always defaults to SSO credentials. How to request for alternate creds?

I have made a bot for a customer.
the purpose is to run admin commands through a secured API.
For this, they need to be
Logged on the teams using their standard account
When they execute an admin command, bot asks for OAuth Login (Connection is set to AzureAD v2 mode).
In teams / tester in portal, it never asks for credentials, it just defaults to the logged on user.
How do I make it always just ask for credentials?
One way is to make a seperate AzureAD, but that then requires customer to pay for Premium AD once again, to be able to assign the AzureAD Roles defined for the admin API to groups and not single users.
So this is not a very good solution.
They can also add teams license to their admin account, but that breaks the whole workflow and reason to have a bot. cause they would have to have a browser open with admin creds logged to teams.
I hope this is possible, otherwise I am super sad, that some amazing admin scenario possibilities are lost. Unfortunately none of our enterprise customers, would allow to trigger various admin APIs using the employees standard account.
I'm not sure if this totally answers your question and I'm a bit confused by what you want. but from what I'm understanding,
I followed this documentation here:https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/add-authentication?tabs=dotnet%2Cdotnet-sample
the sample has a bot that authenticates with azure ad, it pops up the azure log in window every time for me in teams. a please sign in button appears, then you click sign in, and it pops up the login window which then you can get the token for and use that to call graph and etc.
I tested this out and when I talk to the bot, it always asks me to sign in, so hopefully this is what you're looking for? if not, please specify which part its missing, thanks
edit: the instructions are for the aad v1 endpoint, but if you want to use the v2 endpoint, it's nearly the same. just less to type, also you need to enter the scopes that you give api permissions to, eg "User.Read User.ReadBasic.All etc etc"
Update
So upon further discussion I saw what your issue was. what you need to do is the following. in the bot channels registration -> settings -> oauthconnectionsettings, take note of your values and delete it.
Then create a new one, under same name,
with these parameters,
service provider: Oauth 2 Generic Provider
ClientID: same as before
secret: same as before.
scope list delimiter: ' '
authorization URL Template: https://login.microsoftonline.com/common/oauth2/v2.0/authorize (Replace Common with your tenant, just because i was using common)
Auth URL Query string template (this is key): ?client_id={ClientId}&response_type=code&redirect_uri={RedirectUrl}&scope={Scopes}&state={State}&prompt=login
token url template: https://login.microsoftonline.com/common/oauth2/v2.0/token (again replace common with your tenant id)
token url query string tempalte : ?
token body template: code={Code}&grant_type=authorization_code&redirect_uri={RedirectUrl}&client_id={ClientId}&client_secret={ClientSecret}
refresh url template: https://login.microsoftonline.com/common/oauth2/v2.0/token (again replace common with your tenant id)
refresh url query string: ?
refresh body template: refresh_token={RefreshToken}&redirect_uri={RedirectUrl}&grant_type=refresh_token&client_id={ClientId}&client_secret={ClientSecret}
scopes: Mail.Read Mail.Send User.Read User.ReadBasic.All (or whatever your scopes are)

"The tenant for tenant guid ... does not exist" when using client credentials flow (daemon) to access Microsoft Graph API

I want to access Microsoft Graph periodically from a console application in order to copy messages from an Outlook mailbox to a database.
In order to authenticate programmatically, I had to use the Microsoft Graph's "Client Credentials Flow".
These are the steps I had to take:
Register an App in the Azure portal and create a Client Secret for it.
Add all the permissions I need and grant them access:
Have an Admin confirm those permissions by accessing it for the first time. This is done using the following URL:
https://login.microsoftonline.com/{tenant}/v2.0/adminconsent
?client_id={app id}
&state=1234
&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient
&scope=https://graph.microsoft.com/.default
I received the following response:
admin_consent: True
tenant: ca566779-1e7b-48e8-b52b-68**********
state: 12345
scope**: scope: https://graph.microsoft.com/User.Read https://graph.microsoft.com/.default
(The scope might explain the problem described later here: Why do I only get User.Read when I've configured 13 different permissions??)
Get an access token (with success!):
Try to read users (with success):
Try to read my own emails (without success):
Try to read somebody else's emails (the user was invited to access the app as a guest, but still, no success):
I don't understand why I can't read Messages but I can read Users. It seems the permissions were completely ignored (I confirmed that I don't need any permission to read the users).
UPDATE
This is my tenant name:
These are the users added to the tenant:
Important: I don't own an office 365 subscription in my Azure AD. All these emails belong to a different AD.
The previous question "The tenant for tenant guid does not exist" even though user is listed on users endpoint? is similar to mine but I believe this is not a duplicate as my problem is slightly different and the proposed solution uses OAuth1 (I am using OAuth2).
Microsoft Graph can only access data within the tenant you have authenticated to. This means that you cannot access a mailbox from another tenant, even if that User is a guest in the tenant you authenticated to. Allowing this would violate the fundamental principle of data isolation in AAD/O365 tenants.
It is also important to note that AAD/O365 and Outlook.com are distinct platforms. Microsoft Graph's core value prop is a common API layer across AAD and MSA, but under the covers, they are calling into distinct backends.
Beyond data isolation and these being distinct platforms, Outlook.com simply does not support Application Permissions (Client Credentials). You can only access Outlook.com using delegated permissions, and even only a limited set of scopes are supported:
Not all permissions are valid for both Microsoft accounts and work or school accounts. You can check the Microsoft Account Supported column for each permission group to determine whether a specific permission is valid for Microsoft accounts, work or school accounts, or both.
With regards to which scopes are included, I suspect the issue here is that you don't have a license for O365 in this tenant. If it allowed you to consent without a subscription, this could (in theory) lead to apps unexpectedly receiving consent when/if a subscription got added later. That said, it is hard to tell without seeing an example of an actual token you're getting back (feel free to post one of you'd like me to look into this more).
Finally, juunas is also correct with regards to /me. The /me segment is an alias for "the currently authenticated user". Since you are not authenticating a user when you use Client Credentials, /me is effectively null.
/me won't work with a client credentials token.
What would /me refer to? There is no user involved so it cannot mean anything.
For the second problem, does this user have an Exchange Online mailbox in your tenant?
The accepted answer is the one that helped me out. However, I ended-up testing what I needed to test joining the :
Office 365 Developer Program (free)
This program will allow you to create an Azure Active Directory with up to 25 email accounts. It also allows you to create 16 fictitious email accounts with emails inside (by clicking one single button). You can use this infrastructure for 90 days for free.

Azure Active Directory OAuth2 - how to restrict the delivery of tokens to unauthorized apps

I'm trying to configure Active Directory to work in the following use case.
I have 1 API exposed in Azure API Management. I want this API to be called only by authorized apps.
I have created one AD App Registration representing this API and associated an App URI ID.
I have also created one AD App Registration representing my client app.
In POSTMAN, I use an OAuth2 client credentials grant type to get a token and it works. I have a token containing the right audience (= the application App URI ID of my API).
What is very weird is that I didn't do anything regarding permissions between the 2 AD apps. I thought that I need to authorize the client app to use the API app thanks to "API Permissions / Configured Permissions" but it sounds like it is not needed.
But it is not what I'm looking for because I want only authorized apps to be able to get a token with the right audience value.
Am I missing something in the configuration?
By default audience often means 'all APIs using an Authorization Server'. Some - but not all - vendors allow it to be customised in a more fine grained way.
Another option that is sometimes useful is to use custom scopes as high level privileges:
UI 1 includes scope=Orders
UI 2 includes scope=Reports
API 1 requires scope=Orders
If UI 2 calls API 1 you can deny access because it is missing a required scope
This can be a more flexible mechanism than audience, while achieving the same goals
It may not make sense if you are showing these details on consent screens to end users though ..
I found how to proceed, here are the steps:
In the Backend application, we need to set the User assignment required to true
We then need to update manually the manifest of the Backend app to create "app roles". We can create multiple roles to act as "scopes"
Then we need to set API Permissions in the AD Client App to authorize several app roles of the BackEnd App.
Thanks to this configuration, when the client App requests a token, it will obtain it if roles are authorized and the token will contain the list of roles if the "role" claim of the token.
Detail of the configuration is explained in the section of the post: https://github.com/Azure-Samples/active-directory-dotnet-daemon#ensure-that-tokens-azure-ad-issues-tokens-for-your-web-api-only-to-allowed-clients

AAD groups claim missing in JWT token for some users

I'm experiencing some strange behavior on our AAD. After a user signed in successful, we're getting an unauthorized for some users on our API calls. Turns out that a claim in the JWT is missing. Some users are getting the "groups" claim (array of all groupIds he belongs to) and some are getting the "hasgroups" claim (a boolean if the user has groups, no Ids). As our API app is checking this "groups" claim for authorization, the users who don't have this "groups" claim are getting a 403.‬
‪Nevertheless, in the manifest of the app registration I set the “groupMembershipClaims” from “null” to "All" or "SecurityGroup", which should do both the trick. Also set the "oauth2AllowImplicitFlow" to true as we're working with an Angular app which uses OAuth2. Next to that I've compared almost all users settings and apart from some extra groups the users are identical.‬ The affected users don't have a lot of groups, some have even around the 5 groups at max.
Do I overlook something or what's causing this difference in claims? How can I solve this so all users are getting the "groups" claim?
Got this feedback from MSFT internals:
In the implicit flow, oauth will return the Jwt directly from the
intial /authorize call through a query string param. The http spec
limits the length of a query string / url, so if AAD detects that the
resulting URI would be exceeding this length, they replace the groups
with the hasGroups claim.
And this
This is by design when using implicit grant flow, regardless the
"groupMembershipClaims" setting in the manifest. It's to avoid to go
over the URL length limit of the browser as the token is returned as a
URI fragment. So, more or less after 4 user's groups membership,
you'll get "hasgroups:true" in the token. What you can do is to make a
separate call to the Graph API to query for the user's group
membership.
So will need to do an extra roundtrip to Graph API in order to get the user groups. Hope this helps others too.
This is now documented in the Azure AD token reference at https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-token-and-claims.
For the OAuth2 implicit grant flow it uses the hasGroups token and the documentation states for this token:
Used in place of the groups claim for JWTs in implicit grant flows if the full groups claim would extend the URI fragment beyond the URL length limits (currently 6 or more groups).
For other flows:
if the number of groups the user is in goes over a limit (150 for SAML, 200 for JWT) then an overage claim will be added the claim sources pointing at the Graph endpoint containing the list of groups for the user.
You can use the Graph API to obtain a user's groups using https://graph.windows.net/{tenantID}/users/{userID}/getMemberObjects.
Alternatively there is the endpoint at https://graph.windows.net/myorganization/isMemberOf?api-version as documented at https://msdn.microsoft.com/library/azure/ad/graph/api/functions-and-actions#isMemberOf

Microsoft Graph API Multi tenant App-only auth scheme

Microsoft Graph API provides App-only authentication scheme, which works perfectly for the tenant that owns an application.
I have an Azure tenant and I created the application inside it following documentation guide. My application is now able to obtain an access token using https://login.microsoftonline.com/<tenantId>/oauth2/token endpoint, which allows me to query the Graph API for the users inside my tenant.
However, I would like my application to be able to obtain access tokens for other tenants as well. I suppose the external tenant owner should somehow insert my application inside their Azure tenant, apply certain app-only scopes and provide me the tenant id in order to query the token endpoint.
Is multi-tenancy possible for app-only authentication scheme?
How does the tenant owner insert my application into their Azure tenant?
Multi-tenancy for app-only is possible, however, in order to enable this you require two things:
You need to have a web UI for the tenant admin to sign in to and perform admin consent in order to, as you called it, "insert my application into their Azure tenant." Make sure you add the query string parameter &prompt=admin_consent.
More info on admin consent: https://azure.microsoft.com/en-us/documentation/articles/active-directory-devhowto-multi-tenant-overview/#understanding-user-and-admin-consent
Sample controller method that "signs up" the user for an app via admin consent:
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-multitenant-openidconnect/blob/master/TodoListWebApp/Controllers/OnboardingController.cs#L33-L58
You will need to keep track of which tenants consented to your application so that you can enabled the code that runs the app-only flow for them. Unlike the delegated flow, you can't use the common endpoint (https://login.microsoftonline.com/common) but rather need to use the tenant specific endpoint for each instance or run of the app only flow.

Resources