Search code examples
pythonjsonalexa-skills-kitask-sdk

ASK-SDK Python - How do I use multiple permissions in ASK-SDK simultaneously (i.e. reminders and postal code)?


Essentially, I have a skill which already has code for reminders in it: and to check for permissions and ask for them I have the following code:

        ...
        permissions = request_envelope.context.system.user.permissions
        if not (permissions and permissions.consent_token):
            # No permissions exist - ask for them
            logger.debug('Reminder permissions not yet granted')
            
            directive_response = handler_input.response_builder.add_directive(
                SendRequestDirective(
                    name="AskFor",
                    payload={
                        "@type": "AskForPermissionsConsentRequest",
                        "@version": "2",
                        "permissionScopes": [
                            {
                                "permissionScope": "alexa::alerts:reminders:skill:readwrite",
                                "consentLevel": "ACCOUNT"
                            }
                        ]
                    },
                    token="reminder"
                )
            ).response
            logger.debug(directive_response)
            return directive_response

request_envelope.context.system.user.permissions (I logged them):

{
    'consent_token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLjdjNzRjYWQ4LTRlODctNDIyNi04MjI5LWMzMWM0ZjBkNjUyYyIsImV4cCI6MTcwNjUyNTg5NCwiaWF0IjoxNzA2NTIyMjk0LCJuYmYiOjE3MDY1MjIyOTQsInByaXZhdGVDbGFpbXMiOnsiaXNEZXByZWNhdGVkIjoidHJ1ZSIsImNvbnNlbnRUb2tlbiI6IkF0emF8SXdFQklQenBUSFk5em9zY3R2cmpsNEdtanBpbmdQSmhfWWZPb3k5bVptNldkaWZYdHZDX3JRc19lVVRteTUtejQ5UWFVdzNJN0VfMVFQVjZMTktPS1Q3Tm04Vk90ZGgweEwxMGVacTh6R0hDRGhoc3NPQk5HLU5mNFJKZEJlR0VYdFRWcFJqTUVfYnltNE1OZk16WjdGYXNmZmFOSVJzYTBqWDhIcXRIaFVPMzk5TUoyVXBNTTZLdXZpRjZCc1Q0V0U5M1pEZUtZU1VuQzR2aUJGZ0FfOEJhbjNhcE9pcGdaNUdWdE1WS2h3R3psamNBQ2ZXTE5lR01fekpNMDNGVTNnLUl5QW5Yek9XUTl3bnNmUl9CTmdrTVY2ZmVBX01iZzhuaC1DMl9OdHBxTWlWc3JPRFNVMDc0RGFFU19KS01GLURUUTE0IiwiZGV2aWNlSWQiOiJhbXpuMS5hc2suZGV2aWNlLkFNQVZFUFY2NjNGVU40VzRXRUVNMkdIMjZYQUJJS0M2S0gyMzJET00zVU02S1pGVlBaWEYzMllIR1QzUllRREZPNFZRVzNWWDM0NVFETk9JRkpRSk5CN0haNFhNRjNLWlpWSkRDUkRSUDVQUlRWQlNCTElOWkNTRUxRV0ZaMkZRNDNEUjY2T0o0SjRUUzNTS1hWUlg2VksySzMySEQ0N1dOTUpWSFlDNk40UFpFMkU1QzVSNkZCUFIyNUdWQ1M1UEUyWlJIUTZPT0o0NVFWVlQiLCJ1c2VySWQiOiJhbXpuMS5hc2suYWNjb3VudC5BTUE0RkVFSFhZTlQ3VDM0TEk0U0FFWUg2SURTRUlGVDNTNktQRDdZQ0dHS0hPS0lNR1pIQU1DM0pMS1BJTU5DM0JSVjI0WUFUNTJGRVpCNlNTSE5TTlJNSEgzQVBQVkNCVFhGSFE2RzdHNkdUSUs2SEE3S1ZHTkVaSVlENktCWE5ZWFhESjVOUkhHUlhXNFUzNDJPSktJMkRMMkJCU0FRMkRNNkMyTTRXSVA3Q1pWQkhDSlg1RUdDUk9JRDJDN1BVN0hSTDJYVVFEWlBLWjZOVloyV1Q0UktNRExVQjRXSVQ2WDM3NEVKSUxNQSJ9fQ.MGRG4zGyx1PMgti8yG-5SNqpEE7HEW2B1yI3gNL1TCz1Oe7KdmQpbiOqHa8ZW4kEe2ALkWBijwBgFAuW-DMT08j54RpmBUDNdE7gV16W8DYjpGgAk50hBA86pZlCIwrETQx1SvYr1587ttOpsVuH_KyQZ0KdKMQ2h-jCbtct3e2izAzAOGQebR9PEZ2KhtJDQolSlECLCGjg60CUK1bMW7DiEw8jHT2cmSJtlbjma27HSezd0_9n8j5KeuEUFqvGbLNqLABiuhhZ_WZH9bsv2WFb8wQQ0bvauIMiTDdXCBYQDzLG_28D9vNKMIhMLRGjc5HyROdqHeNERffYrRxPkg',
    'scopes': None
}

Directive response:

{
    'api_response': None,
    'can_fulfill_intent': None,
    'card': None,
    'directives': [
        {
            'name': 'AskFor',
            'object_type': 'Connections.SendRequest',
            'payload': {
                '@type': 'AskForPermissionsConsentRequest',
                '@version': '2',
                'permissionScopes': [
                    {
                        'consentLevel': 'ACCOUNT',
                        'permissionScope': 'alexa::alerts:reminders:skill:readwrite'
                    }
                ]
            },
            'token': ''
        }
    ],
    'experimentation': None,
    'output_speech': None,
    'reprompt': None,
    'should_end_session': None
}

I notice that the following code doesn't actually check for the reminder permission specifically, only that any arbitrary permission exists. Now, this would be completely fine in the absence of other permissions, but I am looking to use the postal code permission also - how would this work? My first thought was to use the consent_token in the permissions, but that comes without a key for a token/permission name, and it doesn't come with the response, so I have no way of knowing which consent_token is for which permission. Is there any way to get this working? Help would be much appreciated.


Solution

  • Firstly, consent tokens are deprecated, you should use the context.System.apiAccessToken property instead.

    https://developer.amazon.com/en-US/docs/alexa/custom-skills/device-address-api.html#get-access-token-and-device-id

    There is a gap in the Alexa request format IMO in that if you have multiple permissions available to the user then you don't know which one(s) have been granted. You only get one apiAccessToken and you always get it, regardless of which, if any permissions have been granted. Amazon's "solution" is to call the API associated with the permission you're interested in and see if a 403 (access denies) repsonse is returned. If it is then you know that the user has not granted that permission. Rubbish solution I believe!

    https://developer.amazon.com/en-US/docs/alexa/custom-skills/request-and-response-json-reference.html#system-object

    "This token is included in all requests sent to your skill. When using this token to access an API that requires permissions, your skill should call the API and check the return code. If a 403 (access denied) code is returned, your skill can then take appropriate actions to request the permissions from the user."