OAuth authentication issues using REST API in Python (requests)

Hi! I’m writing an Alexa Skill in Python, in the Alex Skills Kit (ASK). I’m almost there, but having trouble with authentication. Here’s what I’ve done:

I’ve created an App in developer apps. I’ve configured OAuth 2.0 and set the API scope and the callback URL.

In ASK, I’ve created a Linked Account, with the following properties:

* Your Web Authorization URI: https://auth.atlassian.com/authorize?audience=api.atlassian.com
* Access Token URI: https://auth.atlassian.com/oauth/token
* Your Client ID: --Copied from Atlassian App--
* Your Secret: --Copied from Atlassian App--
* Your Authentication Scheme: HTTP Basic
* Scope: write:jira-work
* Domain List: mydomain.atlassian.net

When I open my Skill, I’m taken to the Atlassian authentication page, where the scope is confirmed, and I’m able to select “mydomain.atlassian.net” for use and log in successfully. All is well, and an access_token is return to my Skill.

When I try to use the token to create an issue (Task), however, I get an error. Here’s the code. Note that the access token is stored automatically in handler_input.request_envelope.session.user.access_token:

      # type: (HandlerInput) -> Response
      	rest_url = "https://mydomain.atlassian.net/rest/api/latest/issue/"
        user = handler_input.request_envelope.session.user
        if user.access_token is None:
            speak_output = "Sorry, your account is not linked."
        else:
            # Get task name from slots
            slots = handler_input.request_envelope.request.intent.slots
            task_name = slots['taskName'].value

            data = '{"fields":{ "summary":' + f'"{task_name}"' + ',"issuetype":{ "name": "Task" },"project":{"key":"ABC"}}}'
            data_json = json.loads(data)

            headers = {'content-type': 'application/json', 'authorization': f'token {user.access_token}'}
            response = requests.post(rest_url, headers=headers, json=data_json)
            out = response.json()
            print(response.text)

I get a (bizarre) error:

Field ‘summary’ cannot be set. It is not on the appropriate screen, or unknown

I understand that this is a poorly handled exception and in fact relates to an authentication or authorisation issue.

What am I doing wrong with the use of my token? Have I set up the OAuth side of things correctly? I looked at Jira “Application Links” (as opposed to “Apps”), but these didn’t give me the parameters that I need for 3LO OAuth.

Thank you for your thoughts!

UPDATE 20/10/2020 19:10

I’ve modified my requests code as follows, changing “token” to “Bearer”:

headers = {'content-type': 'application/json', 'authorization': f'Bearer {user.access_token}'}

Now I get a different error:

401: Client must be authenticated to access this resource

1 Like

Me being a complete numpty! I have, of course, now RTFM!

# type: (HandlerInput) -> Response
     user = handler_input.request_envelope.session.user
     if user.access_token is None:
            speak_output = "Sorry, your account is not linked."
        else:
            # Get task name from slots
            slots = handler_input.request_envelope.request.intent.slots
            task_name_slot = slots['taskName']
            task_name = task_name_slot.value

            # Get resources / site id from Jira
            jira_resources_url = "https://api.atlassian.com/oauth/token/accessible-resources"
            headers = {'content-type': 'application/json', 'authorization': f'Bearer {user.access_token}'}
            response = requests.get(jira_resources_url, headers=headers)
            response_json = response.json()
            site_id = response_json[0]['id']

            # Submit API call
            jira_rest_url = f"https://api.atlassian.com/ex/jira/{site_id}/rest/api/2/issue"
            data = '{"fields":{ "summary":' + f'"{task_name}"' + ',"issuetype":{ "name": "Task" },"project":{"key":"PTD"}}}'
            data_json = json.loads(data)
            response = requests.post(jira_rest_url, headers=headers, json=data_json)
            out = response.json()
            print(out)