SOLVED

Validating a user's membership of a Team - Context object

%3CLINGO-SUB%20id%3D%22lingo-sub-842175%22%20slang%3D%22en-US%22%3EValidating%20a%20user's%20membership%20of%20a%20Team%20-%20Context%20object%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-842175%22%20slang%3D%22en-US%22%3E%3CP%3EWe%20should%20use%20the%20values%20from%20the%26nbsp%3B%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fjavascript%2Fapi%2F%40microsoft%2Fteams-js%2Fmicrosoftteams.context%3Fview%3Dmsteams-client-js-latest%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EContext%20object%3C%2FA%3Ewith%20due%20care%2C%20as%20someone%20might%20be%20running%20our%20app%20in%20a%20rogue%20environment%2C%20injecting%20values%20to%20manipulate%20the%20outcome.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EFor%20the%20user's%20login%2C%20I%20understand%20that%20we%20use%20it%20as%20a%20login%20hint%20and%20the%20authentication%20flow%20will%20always%20end%20in%20an%20interactive%20logon%20screen%20if%20that%20login%20hint%20is%20unknown.%20So%20we%20are%20pretty%20safe%20there.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EBut%20what%20about%20the%20organisationId%20%2F%20teamId%20if%20you%20have%20created%20a%20Team%20tab.%20How%20can%20we%20check%20whether%20that%20user%20is%20actually%20part%20of%20that%20team%2C%20if%20we%20only%20have%20user-delegated%20access%3F%20If%20we%20want%20to%20consult%20the%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fuser-list-joinedteams%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3Eme%2FjoinedTeams%3C%2FA%3Eor%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fgroup-list%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EGroups%3C%2FA%3Eendpoints%20of%20Microsoft%20Graph%2C%20we%20need%20admin-level%20consent%20(only%20permissions%20ending%20in%20%22.All%22%20can%20do%20this%20query).%20I%20really%20want%20to%20avoid%20needing%20admin%20consent%20(for%20obvious%20reasons).%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-LABS%20id%3D%22lingo-labs-842175%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3Egraph%3C%2FLINGO-LABEL%3E%3CLINGO-LABEL%3EMicrosoft%20Teams%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E%3CLINGO-SUB%20id%3D%22lingo-sub-843846%22%20slang%3D%22en-US%22%3ERe%3A%20Validating%20a%20user's%20membership%20of%20a%20Team%20-%20Context%20object%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-843846%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F405102%22%20target%3D%22_blank%22%3E%40salvijansen%3C%2FA%3E%2C%20Thanks%20for%20reaching%20us.%20FYI%2C%3C%2FP%3E%0A%3CP%3ESome%20high-privilege%20permissions%20in%20the%20Microsoft%20ecosystem%20can%20be%20set%20to%20%3CEM%3Eadmin-restricted%3C%2FEM%3E.%20Examples%20of%20these%20kinds%20of%20permissions%20include%20the%20following%3A%3C%2FP%3E%0A%3CUL%3E%0A%3CLI%3ERead%20all%20user's%20full%20profiles%20by%20using%3CCODE%3EUser.Read.All%3C%2FCODE%3E%3C%2FLI%3E%0A%3CLI%3EWrite%20data%20to%20an%20organization's%20directory%20by%20using%26nbsp%3B%3CCODE%3EDirectory.ReadWrite.All%3C%2FCODE%3E%3C%2FLI%3E%0A%3CLI%3ERead%20all%20groups%20in%20an%20organization's%20directory%20by%20using%20%3CCODE%3E%3C%2FCODE%3E%3CCODE%3EGroups.Read.All%3C%2FCODE%3E%3C%2FLI%3E%0A%3CLI%3EAlthough%20a%20consumer%20user%20might%20grant%20an%20application%20access%20to%20this%20kind%20of%20data%2C%20organizational%20users%20are%20restricted%20from%20granting%20access%20to%20the%20same%20set%20of%20sensitive%20company%20data.%20If%20your%20application%20requests%20access%20to%20one%20of%20these%20permissions%20from%20an%20organizational%20user%2C%20the%20user%20receives%20an%20error%20message%20that%20says%20they're%20not%20authorized%20to%20consent%20to%20your%20app's%20permissions%3CCODE%3E%3C%2FCODE%3E%3C%2FLI%3E%0A%3C%2FUL%3E%0A%3CP%3E%3CCODE%3E%3C%2FCODE%3EFor%20more%20information%20please%20have%20a%20look%20at%20documentation%20for%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Factive-directory%2Fdevelop%2Fv2-permissions-and-consent%23admin-restricted-permissions%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EAdmin%20Restricted%20Permissions.%3C%2FA%3E%3CCODE%3E%3C%2FCODE%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-844577%22%20slang%3D%22en-US%22%3ERe%3A%20Validating%20a%20user's%20membership%20of%20a%20Team%20-%20Context%20object%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-844577%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F371090%22%20target%3D%22_blank%22%3E%40Trinetra-MSFT%3C%2FA%3E%26nbsp%3BHi%20Trinetra%2C%20thank%20you%20for%20your%20reply!%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI%20know%20the%20reasoning%20behind%20the%20admin-level%20permissions%2C%20but%20at%20the%20moment%20I'm%20not%20able%20to%20check%20the%20team%20id%20I%20get%20from%20the%20Context%20object.%20When%20launched%20as%20a%20team%20tab%2C%20I%20get%20a%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fjavascript%2Fapi%2F%40microsoft%2Fteams-js%2Fmicrosoftteams.context%3Fview%3Dmsteams-client-js-latest%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EgroupId%3C%2FA%3E%26nbsp%3Band%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fjavascript%2Fapi%2F%40microsoft%2Fteams-js%2Fmicrosoftteams.context%3Fview%3Dmsteams-client-js-latest%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EuserObjectId%3C%2FA%3Efrom%20the%20Context%20object.%20So%20Teams%20suggests%20that%20this%20user%20at%20the%20moment%20has%20access%20to%20that%20team%20because%20otherwise%20the%20Context%20object%20would%20not%20contain%20these%20values.%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EAs%20the%20Context%20object%20could%20be%20compromised%2C%20I%20need%20a%20way%20to%20ascertain%20that%20this%20person%20actually%20belongs%20to%20that%20Team.%20I%20should%20be%20able%20to%20use%20the%20%3CEM%3Eme%2FjoinedTeams%3C%2FEM%3Eendpoint%20on%20the%20Graph%2C%20but%20because%20of%20the%20admin-level%20permissions%20required%2C%20I%20cannot%2C%20which%20is%20strange%20as%20it%20is%20actually%20the%20%22me%22%20endpoint%20and%20you%20get%20very%20limited%20information%20back%2C%20not%20an%20actual%20array%20of%20Group%20objects%20(as%20also%20raised%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fuser-list-joinedteams%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3Ehere%3C%2FA%3E%2C%20but%20that%20is%20another%20discussion%20in%20itself).%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3EI've%20raised%20this%20point%20to%20Bill%20Bliss%2C%26nbsp%3BPlatform%20Architect%20and%20Head%20of%20Developer%20Ecosystem%20Microsoft%20Teams%2C%20and%20%3CA%20href%3D%22https%3A%2F%2Ftwitter.com%2Fbill_bliss%2Fstatus%2F1164384562387927040%22%20target%3D%22_self%22%20rel%3D%22nofollow%20noopener%20noreferrer%22%3Ehe%20told%20me%3C%2FA%3Ethat%20more%20fine-grained%20permissions%20are%20coming.%20However%2C%20I'm%20wondering%20whether%20there%20is%20%3CSTRONG%3Eany%20other%20way%20%3C%2FSTRONG%3EI%20could%20ensure%20that%20a%20user%20belongs%20to%20a%20team.%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-856564%22%20slang%3D%22en-US%22%3ERe%3A%20Validating%20a%20user's%20membership%20of%20a%20Team%20-%20Context%20object%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-856564%22%20slang%3D%22en-US%22%3E%3CP%3E%3CA%20href%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fuser%2Fviewprofilepage%2Fuser-id%2F405102%22%20target%3D%22_blank%22%3E%40salvijansen%3C%2FA%3E%20Yes%2C%20You%20can%20use%20your%20group%20id%20to%20fetch%20the%20list%20of%20members%20inside%20team.%20Please%20take%20a%20look%20at%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fgroup-list-memberof%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3EList%20memberOf%3C%2FA%3E%20for%20getting%20list%20of%20members%20in%20a%20team%20using%20Graph%20API.%20You%20can%20call%20this%20API%20endpoint%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fgroup-list-memberof%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fgraph.microsoft.com%2Fv1.0%2Fgroups%2F%7Bgroup-id-for-teams%7D%2Fmembers.%3C%2FA%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-920802%22%20slang%3D%22en-US%22%3ERe%3A%20Validating%20a%20user's%20membership%20of%20a%20Team%20-%20Context%20object%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-920802%22%20slang%3D%22en-US%22%3EmemberOf%20requires%20%22Group.Read.All%22%20which%20needs%20to%20be%20granted%20by%20an%20admin%20and%20as%20I%20have%20said%20twice%20now%2C%20that%20is%20not%20what%20I'm%20looking%20for.%3C%2FLINGO-BODY%3E%3CLINGO-SUB%20id%3D%22lingo-sub-1098702%22%20slang%3D%22en-US%22%3ERe%3A%20Validating%20a%20user's%20membership%20of%20a%20Team%20-%20Context%20object%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1098702%22%20slang%3D%22en-US%22%3E%3CP%3EThere%20seems%20to%20be%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fuser-checkmembergroups%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3Ea%26nbsp%3B%3C%2FA%3E%3CSPAN%3E%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fgraph%2Fapi%2Fuser-checkmembergroups%3Fview%3Dgraph-rest-1.0%26amp%3Btabs%3Dhttp%22%20target%3D%22_self%22%20rel%3D%22noopener%20noreferrer%22%3E%3CSTRONG%3E%3CEM%3E%2FcheckMemberGroups%3C%2FEM%3E%20%3C%2FSTRONG%3Eendpoint%3C%2FA%3E%20which%20can%20be%20reached%20with%20the%20non-admin%26nbsp%3B%3CEM%3EUser.ReadBasic.All%3C%2FEM%3E%20permission%20to%20which%20you%20can%20submit%20the%20user%20and%20the%20groupId%20provided%20by%20the%20Teams%20context%20object%20and%20it%20will%20return%20whether%20the%20user%20is%20actually%20in%20the%20group%20(thank%20you%20to%20the%20MVPs%20%40paulschaeflein%20and%26nbsp%3B%40kevindockx%20!)%3C%2FSPAN%3E%3C%2FP%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%3CP%3E%3CSPAN%3EI'm%20still%20hopeful%20that%20at%20some%20point%20the%20%3CSTRONG%3E%3CEM%3E%2FjoinedTeams%3C%2FEM%3E%3C%2FSTRONG%3E%20endpoint%20can%20also%20be%20reached%20with%20this%26nbsp%3B%3CEM%3EUser.ReadBasic.All%3C%2FEM%3E%20permission%2C%20because%20that%20would%20actually%20%22list%22%20the%20joined%20teams%20with%20their%20id%20and%20could%20be%20used%20when%20you%20don't%20know%20the%20groupId%20upfront.%3C%2FSPAN%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E
Occasional Contributor

We should use the values from the Context object with due care, as someone might be running our app in a rogue environment, injecting values to manipulate the outcome.

 

For the user's login, I understand that we use it as a login hint and the authentication flow will always end in an interactive logon screen if that login hint is unknown. So we are pretty safe there.

 

But what about the organisationId / teamId if you have created a Team tab. How can we check whether that user is actually part of that team, if we only have user-delegated access? If we want to consult the me/joinedTeams or Groups endpoints of Microsoft Graph, we need admin-level consent (only permissions ending in ".All" can do this query). I really want to avoid needing admin consent (for obvious reasons).

5 Replies

@salvijansen, Thanks for reaching us. FYI,

Some high-privilege permissions in the Microsoft ecosystem can be set to admin-restricted. Examples of these kinds of permissions include the following:

  • Read all user's full profiles by using User.Read.All
  • Write data to an organization's directory by using Directory.ReadWrite.All
  • Read all groups in an organization's directory by using Groups.Read.All
  • Although a consumer user might grant an application access to this kind of data, organizational users are restricted from granting access to the same set of sensitive company data. If your application requests access to one of these permissions from an organizational user, the user receives an error message that says they're not authorized to consent to your app's permissions

For more information please have a look at documentation for Admin Restricted Permissions.

@Trinetra-MSFT Hi Trinetra, thank you for your reply!

 

I know the reasoning behind the admin-level permissions, but at the moment I'm not able to check the team id I get from the Context object. When launched as a team tab, I get a groupId and userObjectId from the Context object. So Teams suggests that this user at the moment has access to that team because otherwise the Context object would not contain these values.

 

As the Context object could be compromised, I need a way to ascertain that this person actually belongs to that Team. I should be able to use the me/joinedTeams endpoint on the Graph, but because of the admin-level permissions required, I cannot, which is strange as it is actually the "me" endpoint and you get very limited information back, not an actual array of Group objects (as also raised here, but that is another discussion in itself).

 

I've raised this point to Bill Bliss, Platform Architect and Head of Developer Ecosystem Microsoft Teams, and he told me that more fine-grained permissions are coming. However, I'm wondering whether there is any other way I could ensure that a user belongs to a team.

@salvijansen Yes, You can use your group id to fetch the list of members inside team. Please take a look at List memberOf for getting list of members in a team using Graph API. You can call this API endpoint https://graph.microsoft.com/v1.0/groups/{group-id-for-teams}/members.

 

 

memberOf requires "Group.Read.All" which needs to be granted by an admin and as I have said twice now, that is not what I'm looking for.
best response confirmed by salvijansen (Occasional Contributor)
Solution

There seems to be /checkMemberGroups endpoint which can be reached with the non-admin User.ReadBasic.All permission to which you can submit the user and the groupId provided by the Teams context object and it will return whether the user is actually in the group (thank you to the MVPs @paulschaeflein and @kevindockx !)

 

I'm still hopeful that at some point the /joinedTeams endpoint can also be reached with this User.ReadBasic.All permission, because that would actually "list" the joined teams with their id and could be used when you don't know the groupId upfront.

www.000webhost.com