This is what I have access to from the user:
email_verified
family_name
given_name
name
nickname
picture
sub
updated_at
The api wants an id /api/v2/users/{id}. I tried using the sub but it did not work. How do I get access to the user id? Or what else do I pass in?
When creating a user by posting to /api/v2/users the response contains the user_id as a field. The response you get looks e.g. like this:
{
"email": "john.doe#gmail.com",
"email_verified": false,
"username": "johndoe",
"phone_number": "+199999999999999",
"phone_verified": false,
"user_id": "usr_5457edea1b8f33391a000004", <-- this is the user id
"created_at": "",
"updated_at": "",
"identities": [
{
"connection": "Initial-Connection",
"user_id": "5457edea1b8f22891a000004",
"provider": "auth0",
"isSocial": false
}
],
"app_metadata": {},
"user_metadata": {},
"picture": "",
"name": "",
"nickname": "",
"multifactor": [
""
],
"last_ip": "",
"last_login": "",
"logins_count": 0,
"blocked": false,
"given_name": "",
"family_name": ""
}
You need that id in order to request user data via /api/v2/users/{id}.
If you don't the user_id you can try to get it via the /api/v2/users-by-email endpoint. The information you have according to your question is not enough. What happened to the other information?
EDIT:
What if I am using the lock widget to create users? How can I access
their id , and if not how can I update their information?
You can't create users using the lock widget. The user is registered on a social platform like facebook or google. The lock widget does only authenticate them via that platform any gives you some information about them which you of course can't edit because you do not own that data
Related
I am updating an internally developed single-page app (Typescript/React) that uses OAuth2 from AD-FS 2016 to Azure AD v2. Things are complicated slightly by the fact that I (the developer) don't have direct access to the Azure console and am working on this with a (non-developer) sysadmin who does.
I have implemented PKCE and got the flow working; I can now obtain JWT access, ID and refresh tokens from the server and authenticate them via JWKS. So far so good.
Now, my apps to know a couple more things:
whether or not the user should be treated as an administrator. This is inferred from group memberships
the preferred username and first name/surname of the user
The first of these we dealt with by setting up a "role" and mapping it out to groups in the Azure console. We then added the role claim to the tokens. I can find this as a string array in "id_token". No problem.
I was confused for a while because I was looking for it in "access_token", but it's not a problem for my app to use "id_token" instead.
The second is the thing that is really giving us problems. No matter what we put into the "optional claims" dialog - we've added all these fields and more, for the ID token, they do not appear in it. Nothing we are doing seems to affect the actual tokens that come out at all.
I am beginning to think that I have missed something out with regards to obtaining the information. I am using the https://graph.microsoft.com/profile, https://graph.microsoft.com/email and https://graph.microsoft.com/user.read scopes and the administrator has authorized these on behalf of the app. The user is synced from our in-house active directory, which the AD-FS is running from as well, so I know that this information is in there. I tried messing with the resource parameter but this is deprecated in Azure AD v2 apparently.
I've read and re-read https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims along with other online documentation, and the following passage confuses me and makes me think that the issue might be related to scopes:
Access tokens are always generated using the manifest of the resource, not the client. So in the request ...scope=https://graph.microsoft.com/user.read... the resource is the Microsoft Graph API. Thus, the access token is created using the Microsoft Graph API manifest, not the client's manifest. Changing the manifest for your application will never cause tokens for the Microsoft Graph API to look different. In order to validate that your accessToken changes are in effect, request a token for your application, not another app.
Or is that just the reason that I switched to using the id_token?
The optional_claims section of the configuration manifest looks like this:
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "upn",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "family_name",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "given_name",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "preferred_username",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"accessToken": [
{
"name": "email",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
},
{
"name": "preferred_username",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"saml2Token": [
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": []
}
]
},
But the resulting payload in the ID tag looks like this:
{
"aud": "redacted",
"iss": "https://login.microsoftonline.com/redacted/v2.0",
"iat": 1654770319,
"nbf": 1654770319,
"exp": 1654774219,
"email": "redacted",
"groups": [
"redacted",
"redacted",
"redacted",
"redacted"
],
"rh": "redacted",
"roles": [
"redacted"
],
"sub": "redacted",
"tid": "redacted",
"uti": "redacted",
"ver": "2.0"
}
Can anyone who has more experience of the platform help me understand what we are doing wrong here? Do we need to define custom scopes? Have we simply forgotten to turn an option on?
All help gratefully received! Thanks in advance...
I tried to reproduce the same in my environment and got below results:
I have implemented PKCE flow and got JWT access, ID and refresh tokens.
I added optional claims like below:
Go to Azure Portal -> Azure Active Directory -> App Registrations -> Your App -> Token Configuration
Please check the scopes you are using to get token.
When I gave only openid as scope, got response like below:
But when I gave scope as openid profile email user.read, got all optional claims successfully like below:
I am using Auth0 to authenticate with discord.
The authentication works great with Google and returns a user class filled with information such as username and email. However, when using discord I am returned the below JSON which only has the nickname, name, and picture which are either empty or default.
{
"nickname": "",
"name": "",
"picture": "https://cdn.auth0.com/avatars/default.png",
"locale": "en-US",
"updated_at": "2020-10-31T22:10:50.094Z",
"sub": "oauth2|discord|[REMOVED JUST INCASE]"
}
Here is a picture of the popup login window :
For using Microsoft Graph in our application, I need a token for a specific user. I retrieve a bearer token form Azure Active Directory, but it is missing a refresh_token. It appears that the offline_access permission is being removed from the scopes.
The body of the request I'm sending to the /token endpoint is:
{
code=*somecode*,
client_id=*my clientid*,
client_secret=*my clientsecret*,
redirect_uri=http://localhost:8080/msgraph/callback,
scope=profile Calendars.Read User.ReadBasic.All email User.Read offline_access Calendars.Read.Shared openid,
grant_type=authorization_code
}
I do not use implicit grants. The endpoint I connect to is V2.
In the App registration, I have added all the permissions from the sent scope.
In the token response, all of the requested scopes are returned, except for offline_access. The refresh_token is left empty but I do not receive any errors.
The manifest from the MSGraph administration is
{
"id": "xxxx",
"acceptMappedClaims": null,
"accessTokenAcceptedVersion": 2,
"addIns": [],
"allowPublicClient": null,
"appId": "xxxxx",
"appRoles": [],
"oauth2AllowUrlPathMatching": false,
"createdDateTime": "2018-06-07T07:53:26Z",
"groupMembershipClaims": null,
"identifierUris": [],
"informationalUrls": {
"termsOfService": null,
"support": null,
"privacy": null,
"marketing": null
},
"keyCredentials": [],
"knownClientApplications": [],
"logoUrl": null,
"logoutUrl": null,
"name": "xxxxx",
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": true,
"oauth2Permissions": [],
"oauth2RequirePostResponse": false,
"optionalClaims": null,
"orgRestrictions": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [
{
"customKeyIdentifier": null,
"endDate": "2099-12-31T12:00:00Z",
"keyId": "xxxxx",
"startDate": "2018-06-07T07:58:18.4289954Z",
"value": null,
"createdOn": "2018-06-07T07:58:21.1632167Z",
"hint": "gpi",
"displayName": null
}
],
"preAuthorizedApplications": [],
"publisherDomain": "xxxx.onmicrosoft.com",
"replyUrlsWithType": [
{
"url": "http://localhost:8080/msgraph/callback",
"type": "Web"
}
],
"requiredResourceAccess": [
{
"resourceAppId": "xxxxx",
"resourceAccess": [
{
"id": "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0",
"type": "Scope"
},
{
"id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
"type": "Scope"
},
{
"id": "37f7f235-527c-4136-accd-4a02d197296e",
"type": "Scope"
},
{
"id": "14dad69e-099b-42c9-810b-d002981feec1",
"type": "Scope"
},
{
"id": "465a38f9-76ea-45b9-9f34-9e8b0d4b0b42",
"type": "Scope"
},
{
"id": "2b9c4092-424d-4249-948d-b43879977640",
"type": "Scope"
},
{
"id": "570282fd-fa5c-430d-a7fd-fc8dc98a9dca",
"type": "Scope"
},
{
"id": "7b9103a5-4610-446b-9670-80643382c1fa",
"type": "Scope"
},
{
"id": "f45671fb-e0fe-4b4b-be20-3d3ce43f1bcb",
"type": "Scope"
},
{
"id": "88d21fd4-8e5a-4c32-b5e2-4a1c95f34f72",
"type": "Scope"
},
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
},
{
"id": "b340eb25-3456-403f-be2f-af7a0d370277",
"type": "Scope"
}
]
}
],
"samlMetadataUrl": null,
"signInUrl": "http://localhost:8080/",
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [
"guidedSetupCreatedOrUpdated",
"appModelVersion:2",
"accessTokenVersion:1",
"availableToOtherTenants:true",
"supportsConvergence:true"
],
"tokenEncryptionKeyId": null
}
The request body you posted above isn't in application/x-www-form-urlencoded. Since you're getting an access_token, I'm assuming this is just what you're providing to whichever library you're using to make the actual HTTP request. Just in case, the actual request body should look something like this (line breaks for readability):
grant_type=authorization_code&
code=[AUTHORIZATION CODE]&
client_id=[APPLICATION ID]&
client_secret=[PASSWORD]&
scope=[SCOPE]&
redirect_uri=[REDIRECT URI]
The values your sending looking correct to me with one exception, you shouldn't be passing prompt=consent at this stage.
The prompt parameter is used to force the user to consent during the interactive 1st phase of the flow, not when retrieving the token in the 2nd. It shouldn't result in the behavior you're experiencing but "shouldn't" and "doesn't" are often not the same thing.
If, however, you've added offline_access after the user has consented and you're only passing prompt=consent at this stage, it is possible your app has not received consent for offline_access yet. The token response will only provide scopes that have been consented.
If the user hasn't consented to one of the requested scopes, it will simply not provide that permission rather than returning an error. This allows your app to compare the scopes returned to the scopes requested and allow you to determine if you need to request a reconsent.
To understand why this is/how this works, imagine you request both User.Read.All and User.ReadBasic.All. Since User.Read.All requires Admin Consent, it is possible for a user to login to your app before administrative consent has been granted. In that case, your app may fall back to using User.ReadBasic.All as an alternative. The only difference to the user would be the data you show them would be limited (i.e. maybe your app wants to show displayName and birthday but can fall back to only displayName).
I have analyzed the response from Microsoft today and now it contains the refresh_token! It seems that the is some delay since it did'nt work thursday but works now on monday.
The returned scope in the response still doesn't contain offline_access but the refresh_token parameter is now deliverd.
Thanks for your contributions!
I want details about fields of gmail contact. Using that, i want to create a form a like what is being shown in gmail contact creation page . I could get describe for salesforce contact. i need same for google contact. i give a sample format for lastName
{
"label": "Last Name",
"name": "LastName",
"type": "string",
"createable": true,
"updateable": true,
"custom": false,
"validations": {
"required": true,
"maxlength": 80
},
"scale": 0,
"precision": 0,
"fields": []
}
is there any possible to get this?
The discovery service api describes all of the google apis you can probably get the information from that programmaticlly or you could just check the documentation
You can also check the documentation directly.
Link to People v1 discovery doc
I am able to get access to a user's accessToken, and am making a call to GET https://graph.microsoft.com/v1.0/me with an Authorization: Bearer <token> header.
However, in the response body I'm getting something like this:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users",
"value": [
{
"givenName": "Foo",
"surname": "Bar",
"displayName": "Foo Bar",
"id": "b41efha115adcca29",
"userPrincipalName": "email.address#outlook.com",
"businessPhones": [],
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null
}
]
}
The mail property is null, and the userPrincipalName in this response body happens to the be the user's email address. However, there's this from Microsoft's docs:
Although the UPN and email share the same format, the value of the UPN for a user might or might not be the same as the email address of the user.
When initiating the login request of the user, we're requesting for the "user.read" and "email" scopes. We're using the MSAL.js library to obtain the access token, and our code reads something like this:
login (): ng.IPromise<IMicrosoftOAuthResponse> {
const prom = this.userAgentApplication.loginPopup(["user.read", "email"])
.then((idToken) => {
return this.userAgentApplication.acquireTokenSilent(["user.read", "email"]);
})
.then((accessToken) => {
// at this point, we have the accessToken and make a call to the graph api
});
return this.$q.when(prom);
}
How do I get the actual email address of the user here?
The mail property is set in one of 2 ways:
It's been set on on-premises AD, and then synchronized to Azure AD using AD Connect
The cloud user has been assigned an Office 365 license (and a mailbox), at which point the mail property is set for this licensed user.
If the user does not have an O365 mailbox/license, you could also search for the user by userPrincipalName, displayName, etc. $filter supports the OR operator.
Hope this helps,
Even though this is an old question, I thought I would share my solution to getting the email of a signed-in user. Be aware that this solution requires access to the user's id_token.
The response from calling the /me endpoint looks as follows:
Object {
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": Array [],
"displayName": "John Doe",
"givenName": "John",
"id": "xxxxxx",
"jobTitle": null,
"mail": null,
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": null,
"surname": "Doe",
"userPrincipalName": "johndoe_gmail.com#EXT##johndoegmail.onmicrosoft.com",
}
As we can see, the mail property of this response is null. I am however able to get the user email by decoding the jwt id_token passed along with the access_token when calling the /token endpoint.
By applying the decodeJwtToken() function (attached at the end of this post) to the id_token, I am able to get the user email from the result
Object {
"aio": "xxxxxxxx",
"amr": Array [
"pwd",
],
"aud": "xxxxx",
"email": "johndoe#gmail.com",
"exp": xxxxxx,
"family_name": "Doe",
"given_name": "John",
"iat": xxxxxx,
"idp": "live.com",
"ipaddr": "xxx.xxx.xxx.xxx",
"iss": "https://sts.windows.net/xxxx/",
"name": "John Doe",
"nbf": xxxx,
"nonce": "xxx",
"oid": "xxxxxxx",
"sub": "xxxxx",
"tid": "xxxxx",
"unique_name": "live.com#johndoe#gmail.com",
"uti": "xxxx",
"ver": "1.0",
}
The decoding function looks as follows:
decodeIdToken = (token) => {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(Buffer.from(base64, 'base64').toString().split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
};
For me, https://graph.microsoft.com/v1.0/users/<userid>/authentication/emailMethods endpoint worked. For this, the client must have UserAuthenticationMethod.Read.All permission. One can find more documentation here.
Sample reponse:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('8225f1cd-8025-4f8b-bf94-c595e02e3403')/authentication/emailMethods",
"value": [
{
"id": "3ddfcfc8-9383-446f-83cc-3ab9be4be18f",
"emailAddress": "kim#contoso.com"
}
]
}
var user = graphServiceClient.Users[UserId].Request().Select(x=>x.Identities).GetAsync();
var email = user.Identities.FirstOrDefault().IssuerAssignedId;
create a trial account in microsoft office 365 business premium using the below link:
https://signup.microsoft.com/Signup?OfferId=467eab54-127b-42d3-b046-3844b860bebf&dl=O365_BUSINESS_PREMIUM&culture=en-IN&country=IN&ali=1
Follow the steps while creating the account. It will allow us to create users in office 365. These users are like internal users of an organization. Now open azure portal with the above credential. All users of office 365 will be imported in active azure directory.
Now register an application with Read users basic profile delegated permission in active azure directory. note down client id , client secret and tenant domain to get access token for service to service authentication. This access token can be used to get user records which will be containing mail field as abc#.onmicrosoft.com