I have configured an AD in Azure environment and has granted permissions User.Read and User.Read.All to get user details via graph api. I want to read AD user contact info but api send only below details as mentioned in the documentations.
{
"businessPhones": [
"businessPhones-value"
],
"displayName": "displayName-value",
"givenName": "givenName-value",
"jobTitle": "jobTitle-value",
"mail": "mail-value",
"mobilePhone": "mobilePhone-value",
"officeLocation": "officeLocation-value",
"preferredLanguage": "preferredLanguage-value",
"surname": "surname-value",
"userPrincipalName": "userPrincipalName-value",
"id": "id-value"
}
Azure AD Contact info
Any permissions or any configurations I am missing here to get the rest of the details?
You have to specify the properties you want (source).
Like this:
https://graph.microsoft.com/v1.0/users/<upn or objectId>?$select=streetAddress,state,country,officeLocation,city,postalCode,mobilePhone,businessPhones
Related
When creating multi-tenant apps that will use Azure AD Authentication to sign users in, various samples on GitHub seem to suggest that the App Registration should include the following permissions clubbed under OpenId.
email View users' email address
offline_access Maintain access to data you have given it access to
openid Sign users in
profile View users' basic profile
(See for example: https://github.com/OfficeDev/microsoft-teams-sample-auth-node Section 12)
While following the samples on the Azure portal itself, the quickstarts create an App registration with just this one permission
User.Read Sign in and read user profile
Is Microsoft's Azure AD User.Read permission a superset of the generic openid's email, openid and profile permissions?
When creating a consent URL in the https://login.microsoftonline.com/common/adminconsent?client_id={client-id} form, only the User.Read seems to appear.
What is the recommended set of permissions that are recommended for a basic app that needs to sign users in?
I just spent quite a while testing this as part of my own learning today, and here's what I found.
tl;dr
The openid scope will get you an id_token, and an access_token that allows you to call the UserInfo endpoint (https://graph.microsoft.com/oidc/userinfo). If you want to call any of the Graph APIs, (other than UserInfo) then you'll want (at least) the User.Read scope.
The Details
I have a test AzureAD tenant in which I created a brand-new client app registration (with a SPA endpoint) and a brand-new user, thus ensuring there was no residual 'consent' anywhere.
I then used the browser to sign-in with a hand-crafted URL to request only the openid scope. With line breaks added and some chars redacted this was:
https://login.microsoftonline.com/a8257b21-...6263/oauth2/v2.0/authorize?
client_id=b3f87624-...e5b&
response_type=code&
redirect_uri=https://localhost&
response_mode=query&
scope=openid&
state=12345&
code_challenge=LrTIpxRwK...
code_challenge_method=S256&
prompt=login
For this I got the below consent prompt:
It's interesting to note that it asked to "View your basic profile" and "Maintain access to data..." when I didn't ask for profile or offline_access scopes.
I extracted the authorization code from the response and sent it to the https://login.microsoftonline.com/{{tenant_id}}/oauth2/v2.0/token endpoint with the necessary fields.
The id_token I got back didn't include claims the profile scope would imply, showing only the below
{
"aud": "b3f87624-...2fb5367e5b",
"iss": "https://login.microsoftonline.com/a8257b21...263/v2.0",
"iat": 1642367777,
"nbf": 1642367777,
"exp": 1642371677,
"rh": "0.AUYAIXs...L7U2fluAAB0.",
"sub": "tcK...WXUvzWqAc",
"tid": "a82...6263",
"uti": "SjLRuw...jlhAA",
"ver": "2.0"
}
However interestingly the access_token it returned is for the Graph audience (00000003-0000-0000-c000-000000000000) did list the scopes as including profile and email, and did include claims related to those, e.g. (with some omitted for clarity)
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/a82...6263/",
"app_displayname": "TestApp",
"appid": "b3f87...67e5b",
"family_name": "Bull",
"given_name": "Pit",
"idtyp": "user",
"ipaddr": "67.183.2.129",
"name": "Pit Bull",
"oid": "08a5...673de",
"scp": "openid profile email",
"sub": "6JrD7...phCH7Y",
"tid": "a825...36263",
"unique_name": "pit#example.dev",
"upn": "pit#example.dev",
"ver": "1.0"
}
(Note: Obviously you shouldn't look in tokens that aren't for your audience, but it's all there in clear text, so?)
I did also get a refresh token back, which I saved for later.
With that access token I could call the UserInfo endpoint and also see the *name claims, which would indicate profile scope (I forget to set the email on my test user, else I'm guessing that would have shown too).
From https://graph.microsoft.com/oidc/userinfo
{
"sub": "tcK6D...UvzWqAc",
"name": "Pit Bull",
"family_name": "Bull",
"given_name": "Pit",
"picture": "https://graph.microsoft.com/v1.0/me/photo/$value"
}
However, with that same access token, if I tried to call any Graph APIs such as https://graph.microsoft.com/v1.0/me or https://graph.microsoft.com/v1.0/organization I was met with the following response.
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"date": "2022-01-16T21:52:18",
"request-id": "e4f58...1611",
"client-request-id": "e4f5...a1611"
}
}
}
By running through the same flow again but this time with the scopes openid profile email, the only difference I could ascertain was that the id_token now included the below claims (and again, probably would have had the email address if I'd configured it on the account)
"name": "Pit Bull",
"oid": "08a5...73de",
"preferred_username": "pit#example.dev",
The access token looked the same, and the UserInfo result was the same (which makes sense if the access_token to auth to it looked the same). I'd also note I didn't get prompted for any additional consent, which would imply profile and email were implicitly added to my initial openid-only scope request.
At this point I took a break to feed the kids, and when I came back a couple hours later decided to try out the refresh token I received (without requesting offline_access scope). It worked fine and I got refreshed tokens, so this seems to be implicitly added also when just requesting openid.
For my next test I sent the same hand-crafted request to authenticate but included the User.Read scope. As expected, I got prompted for the additional consent:
It's interesting to note how it mentions "..and read basic company information". This aligns with the docs at https://learn.microsoft.com/en-us/graph/permissions-reference which state of User.Read: "With the User.Read permission, an app can also read the basic company information of the signed-in user for a work or school account through the organization resource.".
All the tokens I got back from this looked similar to before, but obviously with the addition of the User.Read scp in the access token. Now making requests to certain Graph APIs was met with success. For example:
https://graph.microsoft.com/v1.0/me or https://graph.microsoft.com/v1.0/users/pit#example.dev
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "Pit Bull",
"givenName": "Pit",
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": "Bull",
"userPrincipalName": "pit#example.dev",
"id": "08a53...b673de"
}
https://graph.microsoft.com/v1.0/me/directReports (I didn't have any direct reports configured, but it was a successful query rather than access denied)
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#directoryObjects",
"value": []
}
And https://graph.microsoft.com/v1.0/organization (trimmed for readability - and again, I'd not set up org details for this account, hence the nulls)
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#organization",
"value": [
{
"id": "a8257...736263",
"businessPhones": [],
"city": null,
"country": null,
"postalCode": null,
"preferredLanguage": null,
"state": null,
"tenantType": "AAD",
"directorySizeQuota": {
"used": 39,
"total": 300000
},
"verifiedDomains": [
{
"capabilities": "Email, OfficeCommunicationsOnline",
"isDefault": false,
"isInitial": true,
"name": "example.onmicrosoft.com",
"type": "Managed"
},
{
"capabilities": "None",
"isDefault": true,
"isInitial": false,
"name": "example.dev",
"type": "Managed"
}
]
}
]
}
So there you have it. Add User.Read if you want to query anything from the Graph APIs, else just use openid (and optionally profile email) if you are happy just signing users in and using the id_token for your needs.
As a footnote to this I'd also recommend reading the couple paragraphs at https://learn.microsoft.com/en-us/graph/permissions-reference#remarks-15 . I was only testing with a v2 endpoint, but it does look like User.Read used to be required just to sign-in with the v1 endpoint, so it being included by default may be a residual effect of that. As it states of the V1 endpoint: "To successfully return an ID token, you must also make sure that the User.Read permission is configured when you register your app."
Hence the question if user.read subsumes open_id, email and profile
perms?
No, user.read does not contain them, they are independent permissions.
I have set these required perms but in the consent popup shown to the
Azure AD admin, email and profile and openid permissions do not show
up; only offlne_access and user.read shows.
email offline_access openid profile is usually the permissions of the OIDC protocol. There are some differences between oauth2.0 and openid connect. If you only need to log in as a user, you only need to use openid connect, and it will only return you the id token of the logged in user. Regarding why the email openid profile is not displayed on the admin consent page, I think this is a problem that is still being fixed, but I don’t think you need to worry about these because these permissions themselves are permissions that do not require the administrator’s consent. When you add them in API permissions, you can use them directly.
At this time, the offline_access ("Maintain access to data you have given it access to") and user.read ("Sign you in and read your profile") permissions are automatically included in the initial consent to an application. These permissions are generally required for proper app functionality - offline_access gives the app access to refresh tokens, critical for native and web apps, while user.read gives access to the sub claim, allowing the client or app to correctly identify the user over time and access rudimentary user information. please refer to this document
When I use Microsoft Graph API to get a user from Azure AD B2C, the email address that the user has signed up with does not appear in the returned JSON. Although there are posts in SO that suggest the email address should exist in other fields than Mail (otherMails or signInNames), the received JSON does not contain any field whatsoever with the expected email address. Here is the request that I ran for a test user (sensitive data masked):
GET https://graph.microsoft.com/v1.0/users/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Authorization: Bearer xxxxxxxxx
Content-Type: application/json
And the JSON in the response is:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "unknown",
"givenName": "some",
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": "user",
"userPrincipalName": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx#xxxxx.onmicrosoft.com",
"id": "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Despite that, when I see the user in the Azure AD B2C, the email address is displayed under the "User name" column in the users list page:
And when I view the user's profile, the email address also displays under the "User Principal Name" field:
Where is the email coming from, and how can I get it using the MS Graph API?
You can get the username from identities collection using Beta endpoint.
Query
https://graph.microsoft.com/beta/users/userid?select=identities
Please go through the articles
In an Azure Active Directory, I register an App and define application roles in the manifest as follows:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"description": "Normal user access",
"displayName": "User",
"id": "a046aca0-a7c4-4c33-8377-e43c4d7bd89f",
"isEnabled": true,
"value": "User"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Full admin access",
"displayName": "Admin",
"id": "0204f02c-d752-48b5-8b8f-2f8ccb7f83d7",
"isEnabled": true,
"value": "Admin"
}
],
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": true,
Whenever a user receives an access token, the roles are also included. Everything works fine.
Now we have created another Azure Active Directory. I registered an app and define app roles, exactly with same procedure as before. However the roles are not included in the access token. Could someone please help me to cope with this problem?
First please check if you have assigned the user to roles, you can refer to this tutorial.
Second, I'm not sure if you mean access token or id token. As far as I know, the role will not show in access token. It will just show in id token. You can use flow like authorization code grant or openID connect to sign a user in. The response will have a id_token.
Here is another post which is similar to this problem for your reference.
By the way, if we use "client_credentials" as grant type, we can see the permission roles(in appliction permissions) which added in API permissions(the access token contains a roles property). But if we use "password" grant type, the access token will not have this roles property. So please pay attention to the grant type which you used.
Hope it helps.
I have an issue with the Microsoft Graph API.
I have registered a new app in the Azure portal
Added Application.ReadWrite.All and Application.ReadWrite.OwnedBy application permissions
Click on the admin consent button
empty
After that, I'm trying to get an access token by
POST https://login.microsoftonline.com/12fb9222-8b6e-4006-a483-a87fa44621c3/oauth2/v2.0/token
client_id=dc07d452-9ce1-4b0f-a1a6-4fb5b230a4bb
scope=https://graph.microsoft.com/.default
grant_type=client_credentials
client_secret={client_secret}
And I'm getting the token.
Token looks like that:
{
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/12fb9222-8b6e-4006-a483-a87fa44621c3/",
"iat": 1570007742,
"nbf": 1570007742,
"exp": 1570011642,
"aio": "42VgYHi/n737QYBx8DrOTW5Ft0skAQ==",
"app_displayname": "testapp",
"appid": "dc07d452-9ce1-4b0f-a1a6-4fb5b230a4bb",
"appidacr": "1",
"idp": "https://sts.windows.net/12fb9222-8b6e-4006-a483-a87fa44621c3/",
"oid": "24d9cd08-efaf-497b-b023-920cc208400a",
"roles": [
"Application.ReadWrite.OwnedBy",
"Application.ReadWrite.All",
],
"sub": "24d9cd08-efaf-497b-b023-920cc208400a",
"tid": "12fb9222-8b6e-4006-a483-a87fa44621c3",
"uti": "f38JDx5iw0Kkp16mnZIqAA",
"ver": "1.0",
"xms_tcdt": 1569224302
}
After that, I'm executing
GET https://graph.microsoft.com/beta/applications/bb4c22ea-632e-45d8-ad0f-2ba39cf399c1
And I'm getting app properties.
And finally I want to update my app properties and I'm trying execute
PATCH https://graph.microsoft.com/beta/applications/bb4c22ea-632e-45d8-ad0f-2ba39cf399c1
{
"displayName": "displayName"
}
And I'm getting:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "1565bb72-8392-4ca7-bb20-02b40f5603bd",
"date": "2019-10-02T09:23:57"
}
}
}
I'm confused. I have permissions for the API update application, but I got the error, please help.
This seems like a bug, I tried with client credentials and granted Application.ReadWrite.All and Application.ReadWrite.OwnedBy permissions. I encountered the same error as yours.
Then I tried with Delegated permission with a user login, it worked. You can follow this article or just call the api with Microsoft Graph explorer.
Note:
APIs under the /beta version in Microsoft Graph are subject to change.
Use of these APIs in production applications is not supported.
What we are planning to achieve is a role-based security for a Front end Angular-2 and back-end ASP.NET Web API application. We are doing the authentication process with the help of ADAL.js and storing the token in the local storage. We have also implemented the approach shown here i.e. to call the Graphi API and get the user groups to stuff them into Claims.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
The code sample mentioned assign the role based on the group. If you have the Azure AD basic version, it support to assign the role to the users/groups directly.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
Yes, it is possible. To issue the role claims we need to assign the users to assign the roles to users or group first. Then when the user acquire the token, the Azure AD would issue the relative role claims in the token.
You can refer the code sample for using the role claim from here.
And you may also be interest in groups claim developing.
ok i was struggling with this for a while and i have figured it out i believe.
First,
In Azure AD, set up your WebApi app as application type to be Web App / API.
go to Manifest file and add your roles like
[
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]
Then create the the Client app as Application type to be Native app and add required permissions to the service you added above.
In the SPA Angular app add something like this
var endPoints = {
// "https://localhost:44386/" is the API URL
// "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID
"https://localhost:44386/": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};
adalAuthenticationServiceProvider.init({
instance: "https://login.microsoftonline.com/",
// tenant is your tenant name (something like below)
tenant: "{NAME}.onmicrosoft.com",
// this is the Native app application ID (ClientID) you registered
clientId: "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
extraQueryParameter: "nux=1",
endpoints: endPoints
}, $httpProvider);
}
]);
Then, in your startup.cs you need to set up the Service App like the following:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
/* "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID. (Same as you registered in the client app above)*/
ValidAudience = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
RoleClaimType = "roles"
},
/*enant is your tenant name (same as you registered in client app above)*/
Tenant = "{NAME}.onmicrosoft.com"
});
Finally you need to go to Azure active directory => Enterprise application => all applications => select your webAPI service => Users and groups => then assign users to the roles.
When this is all done when you log through your client app to authenticate and call the webapi, adal.js and ada-angular.js will put the proper bearer token that contains roles
Good to learn this approach.
Ted, thanks for sharing your solution !
For those who are not familiar with operating Azure AD manifest file. The following is a good resource.
https://thinkthencode.wordpress.com/2016/04/24/azure-ad-using-app-roles-for-authorization/
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]