API Integration across multiple accounts within same organization - docusignapi

I have had my API Integration promoted to my Production environment for a few weeks now and all is well but I ran into a new issue that I need help understanding. The process is setting up impersonation. The hierarchy of the organization is relatively simple:
My Integration was built under Company A and so far 100% of Company A accounts are able to be impersonated as expected. The issue came up when Company B was added to the Organization and one of the existing accounts was included in the list to be impersonated. The following message is what I am getting back from my API call.
I have Organization Admin permissions as well as Admin permissions on all of the Company Accounts too and this message appears even for me. My feeling is this is a simple administrative function to grant the User in Company A the permissions to access either a User in Company B or all of Company B. I am just not seeing where this gets setup. I hope anyone can point me in the right direction on this one.
=== 07/06/2022 - Adding additional details ===
/oauth/userinfo respose...
{
"sub": "xxxxx-xx-xx-xx-xxxxx",
"name": "Greg Miller",
"given_name": "Greg",
"family_name": "Miller",
"created": "2017-11-10T18:26:23.583",
"email": "greg.miller#companyA.com",
"accounts": [
{
"account_id": "xxxxx-xx-xx-xx-xxxxx",
"is_default": true,
"account_name": "CompanyA",
"base_uri": "https://###.docusign.net",
"organization": {
"organization_id": "xxxxx-xx-xx-xx-xxxxx",
"links": [
{
"rel": "self",
"href": "https://account.docusign.com/organizations/xxxxx-xx-xx-xx-xxxxx"
}
]
}
},
{
"account_id": "zzzzz-zz-zz-zz-zzzzz",
"is_default": false,
"account_name": "CompanyB",
"base_uri": "https://###.docusign.net",
"organization": {
"organization_id": "zzzzz-zz-zz-zz-zzzzz",
"links": [
{
"rel": "self",
"href": "https://account.docusign.com/organizations/zzzzz-zz-zz-zz-zzzzz"
}
]
}
}
]
}
Additional Info Added 07/07/22
Both Company A and Company B base_uri designation is the same "https://na2.docusign.net"
This is the /oauth/userinfo data returned using the JWT created for the Company B user account I am trying to impersonate.
{
"sub": "xxxxx-xx-xx-xx-xxxxx",
"name": "Company B",
"given_name": "CompanyB",
"family_name": "XYZ TEAM",
"created": "2021-03-31T18:20:05.23",
"email": "xyzteam#companyb.com",
"accounts": [
{
"account_id": "xxxxx-xx-xx-xx-xxxxx",
"is_default": true,
"account_name": "Compan B",
"base_uri": "https://na2.docusign.net",
"organization": {
"organization_id": "xxxxx-xx-xx-xx-xxxxx",
"links": [
{
"rel": "self",
"href": "https://account.docusign.com/organizations/xxxxx-xx-xx-xx-xxxxx"
}
]
}
}
]
}
The steps I take are basically the same as you outline:
Generate JWT Access Token
I am manually storing the required userinfo data userID(sub) and base_uri in a local db table.
I am using CURL to make my API calls " $base_uri.'/restapi/v2.1/accounts/'.$AccountID.'/views/console'"

You have two choices for accessing data in Company B (Account B):
Add the user in Company A (Account A) to also be a user in Account B. (Users can have memberships in more than one account.)
To access the data in Account B (Company B), impersonate a (different) user who is in account B. This is done via the eSign Admin app or via the Org Admin app.
By design, a user who is not in Account B cannot access any data in Account B. (This is the error message you're receiving.)
Note: you do not need to make any changes to your app's integration key (client ID)--all client IDs in production can be used with any user, with any account the user has access to.
To see which accounts the current user has access to, use the /oauth/userinfo API method.
Added
When you get the message User does not have a valid membership in this account check:
What account is the request using? (What is the URL of the request?)
Was the request sent to the right base url for the account?
What result does the current access token provide when calling the /oauth/userinfo API method.
Your test API calls should be:
Get an access token
Call /oauth/userinfo
Call the eSign API (eg list envelopes or somesuch) for each of the accounts listed in /oauth/userinfo

Related

How to assign roles to the users in Azure Active Directory

I am creating a login module for a web portal. For this I have created a create user api which creates the user in Azure Active Directory. Below is how I am doing this (in Python) using the Graph API:
user_data = {
"accountEnabled": True,
"displayName": "john",
"mailNickname": "john",
"userPrincipalName": "john#demo.onmicrosoft.com",
"passwordProfile": {
"forceChangePasswordNextSignIn": False,
"password": <password>
}
}
jdata = json.dumps(user_data)
conn = http.client.HTTPSConnection('graph.microsoft.com')
conn.request("POST", "/v1.0/users", jdata, headers)
response = conn.getresponse()
This creates the user in active directory and I am also able to login fine. To login, I am using Python's adal library:
context = adal.AuthenticationContext(config_data['AUTHORITY_HOST_URL'] + '/' + config_data['TENANT'], validate_authority = config_data["TENANT"] != 'adfs')
email = email_name + "#" + config_data['TenantName']
token = context.acquire_token_with_username_password(config_data['RESOURCE'], email, raw_data['password'], config_data['RIPE_CONNECT_CLIENT_ID'])
I also need to assign roles to the user I am creating. For ex, I have education portal where when account is created, user also selects if he/she is student, teacher, parent. Based on this, I need to assign these roles to the user so that whenever user logs in, portal knows that this user is student so it will show all the relevant information and will not show other data which is not relevant to student. When a teacher will log in, it will show all the data.
How can I apply role based control system to users in azure active directory. I have gone through some of the documentation which Microsoft has provided on it but it looks like RBAC is only for the user to restrict their usage of any virtual machine/web service on Azure itself.
How can I use RBAC in my scenario. Is there any API available which I can use to further assign roles to users. What are the other alternatives for this.
Can anyone please give me some good suggestions? Please help. Thanks
EDIT:
config_data['RESOURCE']: https://graph.microsoft.com
Below is the response I get in token when authenticating users using adal library:
{
'tokenType': 'Bearer',
'expiresIn': 3599,
'expiresOn': '2020-10-26 13:19:56.881597',
'resource': 'https://graph.microsoft.com',
'accessToken': 'eyJ0eXAiOiJKV1QiLCJub25jZSI6IjU0aG03Z1psNmdqZVNmT1lCcF9jeVliTWtobklKVmdlV1Q2dHF2SnR3cTgiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtnMkxZczJUMENUaklmajRydDZKSXluZW4zOCIsImtpZCI6ImtnMkxZczJUMENUaklmajRydDZKSXluZW4zOCJ9.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9iYzkwNDExZi03NmI1LTRhYjMtYWZjYS0xM2QxMTI3N2U0NGIvIiwiaWF0IjoxNjAzNjk0Njk3LCJuYmYiOjE2MDM2OTQ2OTcsImV4cCI6MTYwMzY5ODU5NywiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkFTUUEyLzhSQUFBQVJjSi9xVDNnZGY4M25Oc1dMaGV0Tlh1YTNWTEs3ZFF0NERyUXJQMEZUc009IiwiYW1yIjpbInB3ZCJdLCJhcHBfZGlzcGxheW5hbWUiOiJ1c2VyYWNjZXNzIiwiYXBwaWQiOiJjMDFiNjQ4Mi0yODhkLTQ1MzMtOGM5OC1hN2M1ZTgwNjdjYzgiLCJhcHBpZGFjciI6IjAiLCJpZHR5cCI6InVzZXIiLCJpcGFkZHIiOiIxMDMuMTA4LjUuMzQiLCJuYW1lIjoidGVzdHVzZXIiLCJvaWQiOiIxYmM3OTA4NS0yYTFmLTRmYWQtOGRhOC02NDdmNGI0YjI5MjciLCJwbGF0ZiI6IjE0IiwicHVpZCI6IjEwMDMyMDAwQTg5NURGQUQiLCJyaCI6IjAuQVN3QUgwR1F2TFYyczBxdnloUFJFbmZrUzRKa0c4Q05LRE5GakppbnhlZ0dmTWdzQUhFLiIsInNjcCI6IkFjY2Vzc1Jldmlldy5SZWFkLkFsbCBBY2Nlc3NSZXZpZXcuUmVhZFdyaXRlLkFsbCBBY2Nlc3NSZXZpZXcuUmVhZFdyaXRlLk1lbWJlcnNoaXAgQXBwUm9sZUFzc2lnbm1lbnQuUmVhZFdyaXRlLkFsbCBEaXJlY3RvcnkuQWNjZXNzQXNVc2VyLkFsbCBEaXJlY3RvcnkuUmVhZC5BbGwgRGlyZWN0b3J5LlJlYWRXcml0ZS5BbGwgR3JvdXAuUmVhZC5BbGwgR3JvdXAuUmVhZFdyaXRlLkFsbCBNZW1iZXIuUmVhZC5IaWRkZW4gUGVvcGxlLlJlYWQuQWxsIFBvbGljeS5SZWFkLkFsbCBVc2VyLkV4cG9ydC5BbGwgVXNlci5JbnZpdGUuQWxsIFVzZXIuTWFuYWdlSWRlbnRpdGllcy5BbGwgVXNlci5SZWFkIFVzZXIuUmVhZC5BbGwgVXNlci5SZWFkQmFzaWMuQWxsIFVzZXIuUmVhZFdyaXRlIFVzZXIuUmVhZFdyaXRlLkFsbCBVc2VyQWN0aXZpdHkuUmVhZFdyaXRlLkNyZWF0ZWRCeUFwcCBVc2VyQXV0aGVudGljYXRpb25NZXRob2QuUmVhZCBVc2VyQXV0aGVudGljYXRpb25NZXRob2QuUmVhZC5BbGwgVXNlckF1dGhlbnRpY2F0aW9uTWV0aG9kLlJlYWRXcml0ZSBVc2VyQXV0aGVudGljYXRpb25NZXRob2QuUmVhZFdyaXRlLkFsbCBVc2VyVGltZWxpbmVBY3Rpdml0eS5Xcml0ZS5DcmVhdGVkQnlBcHAiLCJzdWIiOiJld1lCcXVQWTRNN2RJazkyaWdQeUdhanlseTlkeFdNd2FxY0YzOHh1MVUwIiwidGVuYW50X3JlZ2lvbl9zY29wZSI6Ik5BIiwidGlkIjoiYmM5MDQxMWYtNzZiNS00YWIzLWFmY2EtMTNkMTEyNzdlNDRiIiwidW5pcXVlX25hbWUiOiJ0ZXN0dXNlckByaXBlZGVtby5pbmZvIiwidXBuIjoidGVzdHVzZXJAcmlwZWRlbW8uaW5mbyIsInV0aSI6IjJGM0pHNW1FMDBXdlR3N2pzN2lDQUEiLCJ2ZXIiOiIxLjAiLCJ3aWRzIjpbImI3OWZiZjRkLTNlZjktNDY4OS04MTQzLTc2YjE5NGU4NTUwOSJdLCJ4bXNfdGNkdCI6MTUyODQ3NjExOX0.qk3t_nZ0q_koA4D1QZNeBm7DLbuYxiCMNn8TC85dyQz1eY1uIZ1jhj7248z0m4CvELtp27KR8-jssiCzkW1RdUgxShscV6jRbmMPcpbR5YZ5iNZOyQxQHDSAafM0s_mJjQAA8JTwxc4yAhcKOU2R5PcVX6zbeCi28weQDs9q6vke7fCN7UPX6MKQNELBopJnQaXrvc5J9UAhvA1-_FfONnjb3zxRqb55hQuAiKpn2pRzyfD_fHViuPD2UauTZ0-1rwLRPtuMWdPl2aZNGrftfgTCeN6kxUlvunta06cdtyN6XnILCCv7mlYecPPwZi4vd5SC0hIYNIaEgciBa1pwYg',
'refreshToken': '0.ASwAH0GQvLV2s0qvyhPREnfkS4JkG8CNKDNFjJinxegGfMgsAHE.AgABAAAAAAB2UyzwtQEKR7-rWbgdcBZIAQDs_wIA9P-wwH63zoGppq4f4Mz_zC7KfHZm8AYjxC3scz2h4HGhhHlmMNHFwj3IxE-EjTu0fgnzW-0YsRe4ELoB-3kD87Ok7NuF91NlLw2jnsVmfBu3WAbpqPDe_dGbJN6jKORHaXnSZFa32CvXht2wfj-VByzqXCBOIA3N6h61zptbSXvw4kRcobMAnftSgrzmIMwvVZIduEfnzkuSphwla_V0UxQhnAioVQUlJP90-5WRoVjLNqrmLQnaTUrY4ppeKL_u12HJZje1T2TmTHqTIfrGOZz_tvEDGsU06D2AbjTrVCfJget6D4UgKtUuo9L_dGS9PFO6OSMHSzAu32tXrB0pgxz9okm-so1ptpcSh1jtbrZATmYG4olBcEmKD_-meVrgQ7r_XH8GseBPXSSw_Bqvr55GDUbm0qGjDc3qUjHnBAeVZOPJVTKaTOK93UoUtv15DXB23UN-8xQjQ6ynjIUfC_mIJVr4m1K_sDjVAqvsvOX_gM0Zc0OwsUvB3-W_fIbr0CO1Rd38s2XfDOwkuqi8GCab6Jao5DC9rMDxekJmrc1efQvexdnijjGoTm__IGFZF2IUR_ARdJxt6UlPVrIpvAJROO5T7YIEpeR-fo6euq6txYDjiw4ImZCZ5E717lbRQsqiqLshV2TZNmf0rqRPesraBqBi8LfvEei7AdYMor5uMZpcnYPx2xKMnEnCrZBj1PkMc-quDhIoWyRNontHmTa2YbrFWGZBf61g2Y6J_P_5qySljS3JZted2A_jVd45ue2aBzcQVjxuXnKn0EEeoeq_dmxEylWxwoZYL_2hBnlNzgGD5gVXf24uL_RJvuIHat68UOSCt6hf4IwVVLGvNobhqPJO5v5YNvHdmP5P1n0KkEQJLzoyZuY',
'oid': '1bc79085-2a1f-4fad-8da8-647f4b4b2927',
'tenantId': 'bc90411f-76b5-4ab3-afca-13d11277e44b',
'userId': 'testuser#demo.info',
'isUserIdDisplayable': True,
'isMRRT': True,
'_clientId': 'c01b6482-288d-4533-8c98-a7c5e8067cc8',
'_authority': 'https://login.microsoftonline.com/bc90411f-76b5-4ab3-afca-13d11277e44b'
}
Response when using client id as resource:
{
'tokenType': 'Bearer',
'expiresIn': 3599,
'expiresOn': '2020-10-26 13:30:30.990330',
'resource': 'c01b6482-288d-4533-8c98-a7c5e8067cc8',
'accessToken': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImtnMkxZczJUMENUaklmajRydDZKSXluZW4zOCIsImtpZCI6ImtnMkxZczJUMENUaklmajRydDZKSXluZW4zOCJ9.eyJhdWQiOiJjMDFiNjQ4Mi0yODhkLTQ1MzMtOGM5OC1hN2M1ZTgwNjdjYzgiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9iYzkwNDExZi03NmI1LTRhYjMtYWZjYS0xM2QxMTI3N2U0NGIvIiwiaWF0IjoxNjAzNjk1MzMxLCJuYmYiOjE2MDM2OTUzMzEsImV4cCI6MTYwMzY5OTIzMSwiYWNyIjoiMSIsImFpbyI6IkUyUmdZTWllNDd1WE15NzlzZXVzTTVjRWZwemJiN2N4MjNOaGw2YklQZmxKVHJxOURDa0EiLCJhbXIiOlsicHdkIl0sImFwcGlkIjoiYzAxYjY0ODItMjg4ZC00NTMzLThjOTgtYTdjNWU4MDY3Y2M4IiwiYXBwaWRhY3IiOiIwIiwiaXBhZGRyIjoiMTAzLjEwOC41LjM0IiwibmFtZSI6InRlc3R1c2VyIiwib2lkIjoiMWJjNzkwODUtMmExZi00ZmFkLThkYTgtNjQ3ZjRiNGIyOTI3IiwicmgiOiIwLkFTd0FIMEdRdkxWMnMwcXZ5aFBSRW5ma1M0SmtHOENOS0RORmpKaW54ZWdHZk1nc0FIRS4iLCJyb2xlcyI6WyJkaXN0cmlidXRvciJdLCJzY3AiOiJBY2Nlc3NSZXZpZXcuUmVhZC5BbGwgQWNjZXNzUmV2aWV3LlJlYWRXcml0ZS5BbGwgQWNjZXNzUmV2aWV3LlJlYWRXcml0ZS5NZW1iZXJzaGlwIEFwcFJvbGVBc3NpZ25tZW50LlJlYWRXcml0ZS5BbGwgRGlyZWN0b3J5LkFjY2Vzc0FzVXNlci5BbGwgRGlyZWN0b3J5LlJlYWQuQWxsIERpcmVjdG9yeS5SZWFkV3JpdGUuQWxsIEdyb3VwLlJlYWQuQWxsIEdyb3VwLlJlYWRXcml0ZS5BbGwgTWVtYmVyLlJlYWQuSGlkZGVuIFBlb3BsZS5SZWFkLkFsbCBQb2xpY3kuUmVhZC5BbGwgVXNlci5FeHBvcnQuQWxsIFVzZXIuSW52aXRlLkFsbCBVc2VyLk1hbmFnZUlkZW50aXRpZXMuQWxsIFVzZXIuUmVhZCBVc2VyLlJlYWQuQWxsIFVzZXIuUmVhZEJhc2ljLkFsbCBVc2VyLlJlYWRXcml0ZSBVc2VyLlJlYWRXcml0ZS5BbGwgVXNlckFjdGl2aXR5LlJlYWRXcml0ZS5DcmVhdGVkQnlBcHAgVXNlckF1dGhlbnRpY2F0aW9uTWV0aG9kLlJlYWQgVXNlckF1dGhlbnRpY2F0aW9uTWV0aG9kLlJlYWQuQWxsIFVzZXJBdXRoZW50aWNhdGlvbk1ldGhvZC5SZWFkV3JpdGUgVXNlckF1dGhlbnRpY2F0aW9uTWV0aG9kLlJlYWRXcml0ZS5BbGwgVXNlclRpbWVsaW5lQWN0aXZpdHkuV3JpdGUuQ3JlYXRlZEJ5QXBwIiwic3ViIjoiXy01cmU1QWY0bjlsdFNETjdQaW5zOFN0QkZSTlR4QUxNaHZLM2QxZi1rNCIsInRpZCI6ImJjOTA0MTFmLTc2YjUtNGFiMy1hZmNhLTEzZDExMjc3ZTQ0YiIsInVuaXF1ZV9uYW1lIjoidGVzdHVzZXJAcmlwZWRlbW8uaW5mbyIsInVwbiI6InRlc3R1c2VyQHJpcGVkZW1vLmluZm8iLCJ1dGkiOiJsNUNBb2dlQm5VV0pzQnktVlBQTkFBIiwidmVyIjoiMS4wIn0.BkjC5-glOieUjsx3QoRs0LuWUbKlX__G9EIDHL3Uxmc1NnTFsAPgi1NdtZuimiP9r6Th976XaHzub_Z6cq_yzRVzQNEon41GGI_mrc3ejjCJnRjgxSTOhQlqiW99E58x6PATPzB2rjwpNj_BOkkAR8qWul-nUxYf071h0RLNqftUigLL85LpkLFSWgBmqp1o7m84Y5lmxPNBsMYoNw7z94lDlR79j-SjwbxhvFO-zaR2qXMw4U2yWHmjxhYx-VJ1goC_esgasutI5PUCndYewzH9pnG9uNTwDFaLpJS_FudQrPSKvr2mVFGqwpuEIfmbybj-Vd2ETPCIu8kZ-b__3g',
'refreshToken': '0.ASwAH0GQvLV2s0qvyhPREnfkS4JkG8CNKDNFjJinxegGfMgsAHE.AgABAAAAAAB2UyzwtQEKR7-rWbgdcBZIAQDs_wIA9P8SUM1Gw4jhn-3gCk4lIUZOSxhqfoeqN6nY7DXdcjtUqsWRbzeB09CdUPwJqkwr42WqsFgQhxRc3NMxt_ZSwut2ZvrapmKCTjXzp3mXzzk3PQulqUQCa0eIgtNhrmjQoQ57L-TkprJnzIrTh2mYQMWDsSJB82jva-5EPi0dmuqvwfmBuWAjJqh1RinAmBZOtl4B5GUqTDvblJMINqV6nNJRESGU51alKLyailCumYDzWlN-ljEdY3O6Y53EwvQBfLbKIckCChXs__Tn0q4UDfmiJpVPdG1K452Jm2IhgCYsp8Uy-pPd2l1ZNObH9Vr5cadkSoAJP9v4I4g7BGokV9J9GiysR7mENhxh_oe3Yao7Mhosmid7Nveplv3BkZxbmilWp_1-11tUrGWEIjz6O1j0i9_0o6UW54SYA5Wj4hFXQ6yQX0x2QBTj7xGJBzsiJ4F3gxuZ_wCZUqyqwkxvqAg8SkK1QUpPQpOlMrfoE-db5jJ4sL1WcQ71ZSD3cfJgLRtajCPIJsutQ-It8FE6rG9Qj8k_srKB6oSKQL62J_X7bUVGLdZRjDVNhWaowam_oz4oNm7z1YELAepOJvpV__PEETAFxpl_zl2WnizKAYsSDMg8U1NZJ11Ihvyh3B_yYUKjPA46iqcWgp0WeUc93L-ZYgIdFy3j1Ie3N7p-hYXCxSdMs0UUnQUcUwgbXnwCfPEwcDdQH0WqwKBAILRml0rR-PAcSY6hUV5g51mQ3mHpfGvTtkIbDEMj2LmwGR872-JOB4gxGn4wv48AuxOrtu-GydcwucY_ev9bKs72XdwXC0vi2KGoVqv5ElJdAqjquf2doxaegCAwFe4APYeQ-AdkyR30CpuJedmp5YBESNTNB4yljreHErk9UXKkCYcCQnk',
'oid': '1bc79085-2a1f-4fad-8da8-647f4b4b2927',
'tenantId': 'bc90411f-76b5-4ab3-afca-13d11277e44b',
'userId': 'testuser#demo.info',
'isUserIdDisplayable': True,
'isMRRT': True,
'_clientId': 'c01b6482-288d-4533-8c98-a7c5e8067cc8',
'_authority': 'https://login.microsoftonline.com/bc90411f-76b5-4ab3-afca-13d11277e44b'
}
I think what you are looking for is app roles and appRoleAssignments: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-approleassignments?view=graph-rest-1.0&tabs=http.
You can define user roles in your app registration manifest, and then assign them through API calls to the endpoint linked above, or through the Azure AD management UI (Enterprise applications -> your app -> Users and groups).
Documentation for app roles: https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
Example defined role from the above docs:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Writer",
"id": "d1c2ade8-98f8-45fd-aa4a-6d06b947c66f",
"isEnabled": true,
"description": "Writers Have the ability to create tasks.",
"value": "Writer"
}
],

How to use same value for AppRoles and oauth2Permissions with different Description and Display name?

My Azure AD application expose scope Roles.ReadWrite.All(Delegated permission). Now I want to use machine to machine communication, So I need to expose Application Permission. From the official documentation How to: Add app roles in your application and receive them in the token, I have created a AppRoles. Now I can give another application Application permission to the application.
But the issue is, I want to use the same value for Application Permission and Delegated Permission, As Microsoft is already doing this with their Microsoft Graph application's AccessReview.Read.All permission. But when I want to create appRoles, it shows an error -
Failed to update Backend API application. Error detail: It contains duplicate value. Please Provide unique value. []
I can only create same permission value if I keep the id, description and display name same for both appRoles and oauth2Permissions. But Microsoft Graph is using two different ID but the same value!
...
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "ebfcd32b-babb-40f4-a14b-42706e83bd28", // AccessReview.Read.All
"type": "Scope"
},
{
"id": "d07a8cc0-3d51-4b77-b3b0-32704d1f69fa", // AccessReview.Read.All
"type": "Role"
}
]
},
{
"resourceAppId": "96954c3d-fbb4-4899-be79-582b810acb7b",
"resourceAccess": [
{
"id": "fbeb72c6-dfcb-45b6-b83a-db2929314e70",
"type": "Scope"
},
{
"id": "42b90870-bbe2-46c6-a221-4f8981c559ae", // Roles.ReadWrite.All
"type": "Scope"
},
{
"id": "42b90870-bbe2-46c6-a221-4f8981c559ae", // Roles.ReadWrite.All
"type": "Role"
}
]
}
],
...
As it is shown in the above Manifest snippet, Graph API's AccessReview.Read.All has two different id for Delegated and Application permission, Where my Roles.ReadWrite.All has same ID as a result same Display Name and Description
I'm afraid that what you need is not supported currently.
As you have tested, if we use the same value for "AppRoles" and "OAuth2Permission", it will show this error: It contains duplicate value. Please Provide unique value.
When we set the same ID for "AppRoles" and "OAuth2Permission", we will be required to set the same value for (description, adminConsentDescription),(displayName, adminConsentDisplayName),(isEnabled, isEnabled),(origin, origin),(value, value).
In this case, we can say that we get the same object for "AppRoles" and "OAuth2Permission". But it will not affect your use. The access token can return the correct Delegated permission or Application permission.

Why do different Microsoft Graph APIs return different data

I'm using the Microsoft Graph Users API to validate a list of user names or email addresses against our ActiveDirectory. The name search:
https://graph.microsoft.com/v1.0/me/people/?$search=john.smith
returns additional data such as officeLocation and jobTitle. But if I use the email search:
https://graph.microsoft.com/v1.0/users/john.smith#company.com
these additional fields are empty. I've enabled these API permissions in Azure:
People.Read
User.Read
User.ReadBasic.All
email
Do I need additional permissions to get the same data?
Update: I tried this in https://developer.microsoft.com/en-us/graph/graph-explorer as suggested below and it works, but Graph Explorer comes with these permissions by default which can't be disabled:
Calendars.ReadWrite
Contacts.ReadWrite
Directory.Read.All
Files.ReadWrite.All
Mail.ReadWrite
Notes.ReadWrite.All
openid
People.Read
Sites.ReadWrite.All
Tasks.ReadWrite
User.ReadBasic.All
User.ReadWrite
Update 2: I'm using Python 3.7 so I borrowed device_flow_session() from https://github.com/microsoftgraph/python-sample-console-app/blob/master/helpers.py#L25. The data I get back from https://graph.microsoft.com/me/people/?$search=John.Smith looks like:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")/people",
"value": [{
"id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
"displayName": "John Smith",
"givenName": "John",
"surname": "Smith",
"birthday": "",
"personNotes": "",
"isFavorite": False,
"jobTitle": "Software Engineer",
"companyName": "Company",
"yomiCompany": "",
"department": "Fish",
"officeLocation": "London",
"profession": "",
"userPrincipalName": "John.Smith#company.com",
"imAddress": "sip:John.Smith#company.com",
"scoredEmailAddresses": [{
"address": "John.Smith#company.com",
"relevanceScore": -6.0991198031917175,
"selectionLikelihood": "notSpecified"
}
],
"phones": [],
"postalAddresses": [],
"websites": [],
"personType": {
"class": "Person",
"subclass": "OrganizationUser"
}
}
]
}
Whereas the data from https://graph.microsoft.com/users/John.Smith#company.com is:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "John Smith",
"givenName": "John",
"jobTitle": None,
"mail": "John.Smith#company.com",
"mobilePhone": None,
"officeLocation": None,
"preferredLanguage": None,
"surname": "Smith",
"userPrincipalName": "John.Smith#company.com",
"id": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
}
Based on my test, I found that the information obtained by these two APIs came from different places.
"officeLocation" returned from /me/people seems to be maintained in SharePoint. You can sign in https://apc.delve.office.com/?u=3df5295a-e4b1-46fe-8969-e715ccd11077&v=editprofile to check it.
"officeLocation" returned from /me or /users/{id | userPrincipalName} is maintained in Azure AD. So you can check it in Azure AD -> Users.
After I update the "Office" in Azure AD, I query with the two endpoints. But they gave me two different result. One (/me/people) is old and the other one (/users/{id | userPrincipalName}) is new. Maybe this will take some time to synchronize. Or maybe they won't sync.
I also test it in Microsoft Graph Explorer. And the "officeLocation"s are different as well. So I'm not sure why Microsoft Graph Explorer works fine for you. But you can dig it along with my ideas.
I hope my findings will be helpful to you.
Each "service" in the Graph (Active Directory, Exchange, SharePoint, etc.) make decisions on the data to return by default in calls. These decisions are made to best suit Microsoft in running the service, not necessarily what callers need. ;) I suggest adding the $select parameter to specify the attributes you require.
From https://learn.microsoft.com/en-us/graph/query-parameters#select-parameter:
Important: In general, we recommend that you use $select to limit the
properties returned by a query to those needed by your app. This is
especially true of queries that might potentially return a large
result set. Limiting the properties returned in each row will reduce
network load and help improve your app's performance.
In v1.0, some Azure AD resources that derive from directoryObject,
like user and group, return a limited, default subset of properties on
reads. For these resources, you must use $select to return properties
outside of the default set.

How to get Organization name from Azure openid?

I want to build a SAAS Service for Azure marketplace using single-sign-on.
I have read this document Microsoft identity platform access tokens, but can not find anything relate to User's Organization.
Is there any way to get user's Organization name?
For now I only can parser from email.
You can call MS Graph API to get the user's organization details: https://learn.microsoft.com/en-us/graph/api/organization-get?view=graph-rest-1.0&tabs=http.
The endpoint is at https://graph.microsoft.com/v1.0/organization
Sample response:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#organization",
"value": [
{
"assignedPlans": [
{
"assignedDateTime": "datetime-value",
"capabilityStatus": "capabilityStatus-value",
"service": "service-value",
"servicePlanId": "servicePlanId-value"
}
],
"businessPhones": [
"businessPhones-value"
],
"city": "city-value",
"country": "country-value",
"countryLetterCode": "countryLetterCode-value",
"displayName": "displayName-value"
}
]
}
You can call this endpoint even with the basic User.Read permission.

Not receiving a request on our MS Graph Webhook for deleting a User in AAD

We created a Webhook for receiving "Delete" notifications when a user is deleted from Azure AD. But we're not receiving any notifications when we delete a user. In AAD the user is first placed in the recycle bin, but also if we remove the user from the recycle bin, we don't receive any notifications.
We've tried our code with receiving emails -> that worked. And with changing a user in AAD -> that also worked. So we changed "updated" to "deleted" and no calls are triggered.
We started with de documentation (https://learn.microsoft.com/en-us/graph/webhooks) and the sample code provided by Microsoft (https://github.com/microsoftgraph/aspnet-webhooks-rest-sample)
We use Permission Scopes:
User.Read.All & Directory.Read.All
Graph Webhook subscription:
Resource: "users"
ChangeType: "deleted"
When we specify "updated" as ChangeType, we received notifications, as expected. But ChangeType "deleted" was not giving any notifications.
Is this not supported, or are we missing a permission...
I hope someone can help.
When you've subscribed to deleted events, you will only get notifications for hard-deleted users. User are almost always "soft-deleted" at first, and then get permanently deleted automatically after 30 days.
For both cases, the permissions User.Read.All is sufficient.
When a user is "soft-deleted" an event is sent to apps subscribed to updated changes. Here's an example (you'll have to trust me that this was due to a soft-delete, since it's the same event for a regular attribute change):
{
"value": [
{
"changeType": "updated",
"clientState": null,
"resource": "Users/514ffc40-afef-4ad9-bc1f-4ad3e425fcec",
"resourceData": {
"#odata.type": "#Microsoft.Graph.User",
"#odata.id": "Users/514ffc40-afef-4ad9-bc1f-4ad3e425fcec",
"id": "514ffc40-afef-4ad9-bc1f-4ad3e425fcec",
"organizationId": "1c411c5e-78cc-4e89-af5e-169408a540b7",
"sequenceNumber": 636921552671905776
},
"subscriptionExpirationDateTime": "2019-05-01T17:13:30.289+00:00",
"subscriptionId": "cfbfa7fc-0771-4394-b563-cff3f8140d02",
"tenantId": "1c411c5e-78cc-4e89-af5e-169408a540b7"
}
]
}
When a user is permanently deleted (either naturally after 30 days, or manually by an admin), apps subscribed to deleted will get a notification. Here's an example:
{
"value": [
{
"changeType": "deleted",
"clientState": null,
"resource": "Users/514ffc40-afef-4ad9-bc1f-4ad3e425fcec",
"resourceData": {
"#odata.type": "#Microsoft.Graph.User",
"#odata.id": "Users/514ffc40-afef-4ad9-bc1f-4ad3e425fcec",
"id": "514ffc40-afef-4ad9-bc1f-4ad3e425fcec",
"organizationId": "1c411c5e-78cc-4e89-af5e-169408a540b7",
"sequenceNumber": 636921556468034066
},
"subscriptionExpirationDateTime": "2019-05-01T17:13:30.289+00:00",
"subscriptionId": "ce04c176-370d-4b67-9da6-05c441186756",
"tenantId": "1c411c5e-78cc-4e89-af5e-169408a540b7"
}
]
}

Resources