New API Permissions requirement?

/v1 app now requires to have all device config selections on the firstPage of the lifecycle in order to keep device permissions. Previously I had device selection on a settings sub-page but it seems like if I put it in a sub-page the app will lose permissions on the UPDATE cycle. This didn’t happen a couple weeks ago?

Is this documented somewhere? Is this intended behavior?

I wasn’t able to replicate the situation you mention, when I update the selected device on the second page, the new access token lets me interact only with the new device.
You should be able to see how the permissions are updated, in the case of deviceSetting, the permissions are formatted as “r:deviceID”. Eg.

 {
  "lifecycle": "UPDATE",
  "executionId": "7d4529fd-...",
  "appId": "c424c087-...",
  "locale": "en",
  "version": "0.1.0",
  "updateData": {
/*This token can also be used from other tools like Postman to check if it is accepted for some endpoints/functions*/
    "authToken": "2ad6a504-...",
    "refreshToken": "24cfc611-...",
    "installedApp": {
      "installedAppId": "1a752ff3-...",
      "locationId": "7770e091-...",
      "config": {
        "temp": [
          {
            "valueType": "DEVICE",
            "deviceConfig": {
              "deviceId": "7ffd2906-...",
              "componentId": "main"
            }
          }
        ],
        "thresholdValue": [
          {
            "valueType": "STRING",
            "stringConfig": {
              "value": "6"
            }
          }
        ],
        "switch": [
          {
            "valueType": "DEVICE",
            "deviceConfig": {
              "deviceId": "7dd1ae0e-...",
              "componentId": "main"
            }
          }
        ]
      },/****This section****/
      "permissions": [
        "r:devices:7ffd2906-...",
        "r:devices:7dd1ae0e-..."
      ]
    },
    "previousConfig": {
      "temp": [
        {
          "valueType": "DEVICE",
          "deviceConfig": {
            "deviceId": "7ffd2906-...",
            "componentId": "main"
          }
        }
      ],
      "thresholdValue": [
        {
          "valueType": "STRING",
          "stringConfig": {
            "value": "3"
          }
        }
      ],
      "switch": [
        {
          "valueType": "DEVICE",
          "deviceConfig": {
            "deviceId": "3265864c-...",
            "componentId": "main"
          }
        }
      ]
    },
    "previousPermissions": [
      "r:devices:7ffd2906-...",
      "r:devices:3265864c-..."
    ]
  },
  "settings": {}
}

Can you share your SmartApp config, please?

I’m only seeing the behavior with Locks. ContactSensor ‘contact’ seems to be working as setup from a sub-page.

Here’s the render result for ‘main’ which is the response for firstPageID on INITALIZE:

{
  "configurationData": {
    "page": {
      "pageId": "main",
      "name": "Configure Lock Manager",
      "nextPageId": null,
      "previousPageId": null,
      "complete": true,
      "sections": [
        {
          "name": "Lock Manager",
          "settings": [
            {
              "id": "members",
              "name": "Edit Members",
              "image": "---",
              "description": "Tap to view",
              "type": "PAGE",
              "page": "members:index"
            },
            {
              "id": "locks",
              "name": "Edit Doors",
              "image": "---",
              "description": "Tap to view",
              "type": "PAGE",
              "page": "locks:index"
            }
          ]
        },
        {
          "name": "Device selections",
          "hideable": true,
          "hidden": true,
          "settings": [
            {
              "id": "locks",
              "name": "Select Locks",
              "type": "DEVICE",
              "required": true,
              "multiple": true,
              "capabilities": [
                "lock"
              ],
              "permissions": [
                "r",
                "x"
              ]
            },
            {
              "id": "contact",
              "name": "Select Contact Sensors",
              "type": "DEVICE",
              "required": false,
              "multiple": true,
              "capabilities": [
                "contactSensor"
              ],
              "permissions": [
                "r",
                "x"
              ]
            }
          ]
        }
      ]
    }
  }
}

Update permission grant request:

I would like to not render the device settings section on this page, but doing so, makes it so that the app does not request permissions for any ‘lock’ device not listed on the “firstPage”

If I render a page like this:

{
  "configurationData": {
    "page": {
      "pageId": "main",
      "name": "Configure Lock Manager",
      "nextPageId": null,
      "previousPageId": null,
      "complete": true,
      "sections": [
        {
          "name": "Lock Manager",
          "settings": [
            {
              "id": "members",
              "name": "Edit Members",
              "image": "---",
              "description": "Tap to view",
              "type": "PAGE",
              "page": "members:index"
            },
            {
              "id": "locks",
              "name": "Edit Doors",
              "image": "---",
              "description": "Tap to view",
              "type": "PAGE",
              "page": "locks:index"
            }
          ]
        }
      ]
    }
  }
}

(Lock and contact device selections happen in the ‘Edit Doors’ page)

Then on the next UPDATE cycle, the user’s permission grant page looks like this:
(note missing grant permission for ‘lock’ device)

Thanks for the info.
I’d like to confirm some details in order to have a configuration as similar as possible and check where’s the issue.
As I understand, your use case is the following:

  • On the “main” page, there are the links to the “members:index” and “locks:index” pages (pageSetting)
  • In the “members:index” page, I guess you select which members your Lock Manager will create the deviceSettings for
  • Then, on page “locks:index”, the device settings are created based on the selected members to define if they have access to the device (Door sensor and lock).

The flow you follow is:

  1. Enter to the SmartApp (“main” page).
  2. Go to the link of “members:index” page, select some members.
  3. Go back to the “main” page and enter the “locks:index” page.
  4. Select the sensors for each member and go back to the main page.
  5. Click on “Done”. It redirects you to the “permissions” page and click on “Allow” to install (first time)
  6. Open the SmartApp again and perform steps 2 - 4.
  7. In this case when you click on “Done” and see the “permissions”, they are incorrect and in the SmartApp payloads, you also see there’s no permission included for the missing device?

Not quite. I’ll give you more screenshots and maybe that will help you visualize my app.

My app must be initialized on my back-end, so when the user first sets up the app, they set it up with minimal configs and click ‘Done.’ Then my app initializes some data and does some API requests to SmartThings to fetch things like scenes and names for devices. This is relivent for scene trigger options and more features later down the line.

Initialize Page:

This page will only display once.

Main Page:

This page is just a landing page. It has links and will display errors such as when a code failed to set on a lock. It has links to other pages where config options live.

Member Index:

members:index is an index of members. An app can have 0 - N members:

Here, you can create a new member by pressing “Create” or tap an existing member to go to their ‘SHOW’ page, and edit their configs.

Member Show:

Members don’t get ‘sensors’ or ‘locks’, they can get access TO those things.

members are generated by my app with tokens, such as ‘xu1Q7Uv’ and variables are stored with a schema: model:variable:token… so a member ‘label’ will be:

member:label:xu1Q7Uv
member:code:xu1Q7Uv
member:unlock_scenes:xu1Q7Uv
member:lock_scenes:xu1Q7Uv
member:enabled:xu1Q7Uv
member:gravatar_email:xu1Q7Uv

This is why, in my previous request I asked for the ability to delete config vars… because if a user decideds to delete ‘xu1Q7Uv’ then the app will have tons of variables saved in the CONFIG that are no longer needed.

But that’s not the point of this thread, just illustrating more frustrations.

Lock Index

This is the lock INDEX page where I show all the doors setup in the app. This is where I’d like to allow the user to select Locks and Sensors to manage within the app. It also displays a list of locks and a link to go into the ‘lock:show:<token>’ page. Locks are also saved with a token under the same schema as before ‘model:variable:token’ because members can have 0 - N locks.

If I put the CONFIG for ‘DEVICE’ with id: ‘lock’ in the page ‘locks:index’, then if a user clicks ‘done’ in the ‘main’ page, the app will not ask for permissions for the CONFIG ‘locks’

Lock show page


The lock SHOW page shows options for the user to edit settings for an individual lock.

NOTE: Selecting ‘which contact sensor’ here is NOT a SmartThings Device select but a reference to the CONFIG option in the previous page. This config just does a relationship match between the lock and a contact sensor to create the concept of a ‘door.’

Issues:

  • I don’t render the config for DEVICE ‘locks’ on the ‘main’ page, the grant request will only ask to grant for ‘sensors’ and not ‘locks’ so that my app will lose access to ‘locks’, To fix this, my app just has to render the configs for devices on the ‘main’ page.
  • N+ of config options are still clunky. As I continue development on this, its more apparent that this will be an issue, as there’s no option to delete stale variables in CONFIG. (separate issue I talked about before)
2 Likes

TLDR;

I think the steps to reproduce the issue is to:

  1. Have the firstPage be a page to a link to another page which will show a device select for a Lock.
  2. Navigate to that second page and select a lock.
  3. Click ‘DONE’ on the second page. SmartThings grant access request to the user will include permissions for the lock.
  4. Go back to your app again and render the firstPage. Click DONE on firstPage. The SmartThings grant permissions UI will NOT include the lock. After clicking ‘DONE’ the app will get a new authToken that will no longer have privileges to those locks.

It seems to be only lock device types that have this behavior in my testing.

Thanks for the details, they were very helpful. Let me say your SmartApp looks awesome!
I made a sample to replicate the steps you mentioned, but I don’t get the error, I keep seeing the correct permissions after the update in both systems, Android and iOS.
I know you’re not using the SDK, but here I share with you my sample and the logs, I think your issue could be related to the config map sent in the UPDATE request.