How can we help? How can we help?
How can we help?

Drop us a line and we’ll get back to you asap!

    Thank you for your inquiry with DVG! We will reach out as soon as possible.

    ArcGIS Survey123 is a spatially enabled form based survey technology that can be paired with automation tools by using the webhooks feature of Survey123. One of the most widely used integrated automation tools used with Survey123 is Microsoft Power Automate (PA) and Azure Logic Apps (the cloud version of Power Automate). The goal of this blog is to focus on securing Power Automate workflows when using the ArcGIS Survey123 connector with a non-public Survey123 form that can only be used by certain users (via Group membership) within ArcGIS Online. The example provided will focus on Power Automate, but also applies to Azure Logic Apps.

    The challenge is that by default, the PA workflow will accept any request that is sent to it as long as the URL and expected parameters are formatted correctly. This provides an opportunity for a bad actor to send a malicious request by simply changing the request body for the workflow to process. To avoid this situation, we will implement token based authentication and authorization on the PA workflow using the user token sent in the Survey123 payload. This achieves the following goals:

    1. Authenticates and authorizes the user who submitted the survey
    2. Avoids abuse of your workflow and prevents running unnecessary workflow actions (each costs money).

    Lets get to it. The outline of the blog is below:

    Workflow Example

    1. Create & Share Survey. First create a Survey123 form and share it with a AGO group that only certain users have access to, or your Organization. Below, I restricted access to the “Favorite Map Projection Group” group, which has a test user in the group.
    Survey123 webhook, power automate, azure logic apps, security
    Survey123 webhook, power automate, azure logic apps, security

    2. Create Triggered Cloud Flow. Next, create a Power Automate “Automated Cloud Flow” that is triggered by ArcGIS Survey123

    Survey123 webhook, power automate, azure logic apps, security

    3. Sign In & Choose Survey. This will open up the workflow editor. If this this the first time you have used the Survey123 connector, you will need to sign in. Following sign in, choose the Survey from the dropdown in the trigger.

    Survey123 webhook, power automate, azure logic apps, security

    4. Check the User. Now the fun part. Next, we are going to check if the user who submitted the survey can be authenticated and if they are authorized to use the form. To do this, we are going to use the AGO /self endpoint to validate the user token and inspect if the user has access the group. First, make a GET request to https://www.arcgis.com/sharing/rest/community/self (see below, doc can be found here https://developers.arcgis.com/rest/users-groups-and-items/self.htm) using the Portal Info Token from the survey. Then, use the Parse JSON function to parse the response to gain access to the parameters. I included an example /self response below, as well as the JSON Schema. Note: I changed the JSON schema object to include only key/values in the JSON that I think are useful in order to avoid data type issues, so you can copy/paste this directly.

    Survey123 webhook, power automate, azure logic apps, security

    If the user is authorized, AGO will return HTTP 200 it will look like the JSON Response section. If the user is not authorized, AGO will still return and HTTP 200 (rather than HTTP 4XX). Importantly, the response JSON will have a different format than the success response and will indicate that there was an error, thus indicating the user cant be authenticated/authorized.

    {
        "error": {
            "code": 498,
            "message": "Invalid token.",
            "details": []
        }
    }

    5. Evaluate Token Validity using “run after” branching. The fact that the HTTP code is 200 and the format is different creates an issue for the Parse JSON tool because it will fail if you get the not authorized response. The way to deal with this is to use Power Automate “run after” behavior. To do this, create parallel branches and add a Scope control action to each branch. In the Scope action, click the settings “run after” to set the behavior. The image below shows these setting for one side of the branch if the Parse JSON fails (left), or if it succeeds (right).

    Survey123 webhook, power automate, azure logic apps, security

    6. Check Group Membership. Next evaluate if the user is a member of the “Favorite Map Projection Group”. To do this, use the Apply to Each on the “groups” array from the Parse JSON response. For each item in the list, check if it equals “Favorite Map Projection Group”. If it does, set the global variable “IsPartOfGroup” to true. (I didn’t show this above, but add this action above Parse JSON). Then this variable to either proceed with processing or not. See screenshot below for details. In order to grab the right value from the array, you can use the expression below, or choose the “title” parameter from the expression list.

    items('Apply_to_each_-_Each_Group')?['title']
    Survey123 webhook, power automate, azure logic apps, security

    7. Do Useful Stuff. Now, all that you need to do is add another conditional control to evaluate IsPartOfGroup. If its true, run your workflow logic. If it’s false, the user is valid but does not have access to the group and your logic should not run.

    Survey123 webhook, power automate, azure logic apps, security

    Summary

    This workflow demonstrates how to use the Survey123 payload token to ensure the person who is submitting the form is valid and guards against abuse of your workflow HTTP endpoint. The main idea here is that since the token has an expiration, the chances of abuse will be greatly diminished. All of this applies to Azure Logic Apps as well. An alternative building this logic is to use Azure Function Apps to run the /self HTTP call as well as handling the logic of if the user is authorized or not, then connect your workflow directly to the function app. This reduces cost and complexity of the workflow. The full workflow can be seen below.

    Full Workflow

    Survey123 webhook, power automate, azure logic apps, security

    self JSON Response Authenticated/Authorized

    
        "username": "jsmith_test",
        "udn": null,
        "id": "XXXXXXXXXXXXXXXXXXXXX",
        "fullName": "John Smith",
        "categories": [],
        "emailStatus": "notverified",
        "firstName": "John",
        "lastName": "Smith",
        "preferredView": null,
        "description": null,
        "email": "test@email.com",
        "userType": "arcgisonly",
        "idpUsername": null,
        "favGroupId": "XXXXXXXXXXXXXXXXXXXXX",
        "lastLogin": 1660228340000,
        "mfaEnabled": false,
        "storageUsage": 1633444547,
        "storageQuota": 2199023255552,
        "orgId": "XXXXXXXXXXXXXXX",
        "role": "org_publisher",
        "privileges": [
            "features:user:edit",
            "portal:publisher:bulkPublishFromDataStores",
            "portal:publisher:publishDynamicImagery",
            "portal:publisher:publishFeatures",
            "portal:publisher:publishKnowledgeGraph"
    
        ],
        "level": "2",
        "userLicenseTypeId": "creatorUT",
        "disabled": false,
        "tags": [],
        "culture": "en-US",
        "cultureFormat": "us",
        "region": "US",
        "units": "english",
        "thumbnail": null,
        "access": "org",
        "created": 1556539733000,
        "modified": 1620140529000,
        "provider": "arcgis",
        "groups": [
    
    
            {
                "id": "XXXXXXXXXXXXXXXXXXXXX",
                "title": "Favorite Map Projection Group",
                "isInvitationOnly": true,
                "owner": "efarrell_DVG",
                "description": null,
                "snippet": null,
                "tags": [],
                "typeKeywords": [],
                "phone": null,
                "sortField": "title",
                "sortOrder": "asc",
                "isViewOnly": false,
                "featuredItemsId": null,
                "thumbnail": null,
                "created": 1660230048000,
                "modified": 1660230048000,
                "access": "private",
                "capabilities": [],
                "isFav": false,
                "isReadOnly": false,
                "protected": false,
                "autoJoin": false,
                "notificationsEnabled": false,
                "provider": null,
                "providerGroupName": null,
                "leavingDisallowed": false,
                "hiddenMembers": false,
                "membershipAccess": "org",
                "displaySettings": {
                    "itemTypes": ""
                },
                "properties": null,
                "userMembership": {
                    "username": "jsmith_test",
                    "memberType": "member"
                }
            }
        ],
        "appInfo": {
            "appId": "survey123hub",
            "itemId": "XXXXXXXXXXXXXXXXXXXXX",
            "appOwner": "esri_apps",
            "orgId": "XXXXXXXXXXXXXXXXXXXXX",
            "appTitle": "ArcGIS Survey123",
            "privileges": [
                "features:user:editIndoorsSpaces",
                "premium:user:demographics",
                "premium:user:elevation",
                "premium:user:geocode",
                "premium:user:geocode:stored",
                "premium:user:geocode:temporary",
                "premium:user:geoenrichment",
                "premium:user:networkanalysis",
                "premium:user:networkanalysis:closestfacility",
                "premium:user:networkanalysis:locationallocation",
                "premium:user:networkanalysis:optimizedrouting",
                "premium:user:networkanalysis:origindestinationcostmatrix",
                "premium:user:networkanalysis:routing",
                "premium:user:networkanalysis:servicearea",
                "premium:user:networkanalysis:vehiclerouting"
            ]
        }
    }

    self JSON Schema

    {
        "type": "object",
        "properties": {
            "username": {
                "type": "string"
            },
            "udn": {},
            "id": {
                "type": "string"
            },
            "fullName": {
                "type": "string"
            },
            "categories": {
                "type": "array"
            },
            "emailStatus": {
                "type": "string"
            },
            "firstName": {
                "type": "string"
            },
            "lastName": {
                "type": "string"
            },
            "preferredView": {},
            "description": {},
            "email": {
                "type": "string"
            },
            "userType": {
                "type": "string"
            },
            "idpUsername": {},
            "favGroupId": {
                "type": "string"
            },
            "lastLogin": {
                "type": "integer"
            },
            "mfaEnabled": {
                "type": "boolean"
            },
            "storageUsage": {
                "type": "integer"
            },
            "storageQuota": {
                "type": "integer"
            },
            "orgId": {
                "type": "string"
            },
            "role": {
                "type": "string"
            },
            "level": {
                "type": "string"
            },
            "userLicenseTypeId": {
                "type": "string"
            },
            "disabled": {
                "type": "boolean"
            },
            "tags": {
                "type": "array"
            },
            "culture": {
                "type": "string"
            },
            "cultureFormat": {
                "type": "string"
            },
            "region": {
                "type": "string"
            },
            "units": {
                "type": "string"
            },
            "thumbnail": {},
            "access": {
                "type": "string"
            },
            "created": {
                "type": "integer"
            },
            "modified": {
                "type": "integer"
            },
            "provider": {
                "type": "string"
            },
            "groups": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "id": {
                            "type": "string"
                        },
                        "title": {
                            "type": "string"
                        }
                    },
                    "required": [
                        "id",
                        "title"
                    ]
                }
            }
        }
    }
    ArcGIS Survey123 Webhook + Power Automate Token Security

    Share On:

    Verified by MonsterInsights