Share Power Apps without Security Groups
Tags: powerapps, powerplatform, lowcode, alm
Published: 2023-06-14 07:59:49

Security groups are great, and the way you should always go to control access to your apps/run only flows. 

But as a citizen developer you might not always have access to security groups, and then you are left with the only option to share users individually, or are you....

There are a couple of things we need,

1. Somewhere to store users
2. Way to add user to app
3. Give user Basic User Security Role
4. Way to remove user from the app

## 1. Somewhere to store users
There is always one place a Power Platform developer falls back to for data storage, and that's SharePoint. We could do this in Dataverse but SharePoint is free and easy.

Our SharePoint list needs 4 columns

![sharepoint list](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vs9pffcc4sfskwrh6agd.png)

- AppID (renamed Title) - the id of your app from details page
- EnvironmentID - the id of the apps environment
- User - person field selecting who you want to give/remove access
- Status - choice field

![status field](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbwkjunrxz7kuolr51q8.png)

AppID and EnvironmentID could be hardcoded into the flow, but this gives ease of reusability for dev/test/prod or even other apps.
Status is what we use to trigger the flow.

2. Way to add user to app

PowerApps Admin connectors to the rescue, as we can use the 'Edit App Role Assignment' to share our app,

![app role assignment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5xsxgukc5r2xpwf2cwk8.png)

But before that we need a trigger, and that's our SharePoint When an item is created or modified, we need a trigger condition to only run when we want it to:

```
@or(equals(triggerOutputs()?['body/Status/Value'],'Request Access'),equals(triggerOutputs()?['body/Status/Value'],'Request Removal'))
```
If its a Request to add or remove, if the status isn't changed to one of these then it wont run.

Next we need to get the Users id. You can use the 'Get_user_profile_(V2) connector, but only if your SharePoint uses your User Principal Name Email address. In my tenant it doesn't so I have to search by email and use the first item.

Now we have to configure the Edit App Role Assignment connector, the connector is made so that you can bulk add users but we are only going to add one. You can use the input fields but to make life easier I use the json view.

![app roles connector settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5anxdhtdso81fm48zm8x.png)

```
[
  {
    "properties/principal/email": "@{outputs('Search_for_users_(V2)')?['body/value'][0]?['userPrincipalName']}",
    "properties/principal/tenantId": "{yourTenantID}",
    "properties/principal/id": @{outputs('Search_for_users_(V2)')?['body/value'][0]?['id']},
    "properties/principal/type": "User",
    "properties/NotifyShareTargetOption": "2",
    "properties/roleName": "CanView"
  }
]
```

If you want to send a shared with email then change `NotifyShareTargetOption` to 1.
Additionally if you want to give the maker access change `roleName` to CanEdit.

## 3. Give user Basic User Security Role
Not all apps need the user to have Basic User security role, but I that think is more of a bug so we really should be adding it to the user.
To do it we now need to edit Dataverse, so we need 2 things

- System Admin/ System Customizer Security Role
- Premium License

If you don't have them you can try without this stage and fingers crossed it might still work.

First we need to find our user in the Users table.

![dataverse user table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jn7wt54ppeot7oidivh9.png)

We use the userPrincipalName again and request just one row count

```
outputs('Search_for_users_(V2)')?['body/value'][0]?['userPrincipalName']
```

Next we need to find the id of the Basic User Security Role (If you wanted to give them maker access then share the Environment Maker Role instead).

![security roles](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zygowtuoyrp7nosbkcug.png)

Finally we need to create a relationship between the 2 tables i.e. give the user the security role.

![dataverse relate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mqmmnaxiwvxxwky6tsez.png)

**Row ID**
```
outputs('List_rows_users')?['body/value'][0]?['systemuserid']
```
**Relate with**
```
outputs('List_rows_roles')?['body/value'][0]?['@odata.id']
```

Adding the user to the app should automatically add them to the user table, but it might take a few seconds so a delay should be added in-between the Edit App Role Assignment and the List rows

![flow steps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwotp2th49hefpzc8qo8.png)

As you can see the last action is to update the SharePoint item to Status 'Access Granted'. Note this is why the trigger condition is so important else you would end up with an infinite loop as the update would be a modification and trigger the flow again.

## 4. Way to remove user from the app
Removing is very similar but easier as we don't need to remove the security role access (as no harm in having it and they can't use it without access to an app).

We need to add a condition after the O365 Search for users(V2) which selects to either add or remove. Then we use the Edit App Role Assignment connector again but pass the users id into the delete id (the same id used in the add action).

![remove user action](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8o7rr9np75qdhnx3lpk.png)

Final step is to update the SharePoint item to Access Removed.

![update sharepoint item](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/07woa4cl8f0uzr6lutlr.png)

---
I wouldn't recommend this as the solution to go with, as Security Groups are far better, but as developer (particulary a Citizen Developer) we don't always have access to everything, and it's nice to know there is always a workaround.